domingo, 20 de diciembre de 2015

CapicuaGen: Proyecto de generador de codigo

Me encuentro estos días por comenzar mi proyecto de fin de master en "Investigación en ingeniera de software". Después de mucho debatir el tema decidí hacer un producto orientado a la generación automática de código, y a la construcción de software desde un enfoque generativo. ¿Que quiere decir esto? Bueno básicamente que construiremos un software, cuya misión es construir otro software, o mas exactamente el código de dicho software. El generador de código que voy a hacer se llamara CapicuaGen, nombre que elegí de forma aleatoria entre varias opciones, y espero, quizás, publicarlo como GPL (o otra licencia afín). En los siguientes meses iré publicando los avances que vaya haciendo en este tema y según sea posible el código fuente, quizás en GitHub.

Para comenzar, publico la propuesta del proyecto, sobre la que voy a comenzar a construir.

Situación actual


Durante la creación de sistemas empresariales, es común que se den las siguientes circunstancias:

  • Software muy parecido a desarrollos anteriores, pero lo suficientemente diferente para impedir que se reúse software y librerías de una forma clara y consistente.
  • Cortos tiempo de desarrollo.
  • Numero de recursos limitados (tanto económicos como humanos).
  • Equipos que atacan varios frentes que no tiene que ver con el sistema a desarrollar en cuestión (los recursos desarrollando o soportando varios sistemas a la vez).

El resultado de toda esta combinación de factores causa los siguientes problemas en el desarrollo de un sistema:

  • Lentitud en el desarrollo.
  • Retrasó en los tiempos de entrega.
  • Elevación de costos.
  • Multitud de horas extras realizadas por el equipo, lo que a su vez en la motivación de este.
  • Sacrificios en la calidad del sistema, lo que a su vez lleva a fallos en el sistema.

Como conclusión impactamos aspectos relativos al producto en si, como la calidad y el tiempo de entrega, y por otro lado impactamos en el equipo de personas que trabaja en el sistema.

Objetivos


Los objetivos a conseguir son los siguientes:

  • Agilizar la construcción de un sistema a partir del uso de generadores de código, que creen de manera adecuada las características comunes de cada sistema, ensamblándola apropiadamente.
  • Reducir la programación manual de un sistema a los elementos particulares que así lo requieran, esto es, aquellos elementos que son exclusivos del sistema y por lo tanto no están incluidos en otros sistemas.

Con el cumplimiento de estos dos objetivos se espera satisfacer las siguientes necesarias:

  • Aumento de la calidad del software al generarse en parte de forma automática. Los fallos detectados se podrían corregir en los elementos generadores y aplicar automáticamente al código de los sistemas.
  • Los codificadores no perderían tiempo realizando tareas repetitivas y se concentraría en las tareas que realmente da valor al sistema, y no en aquellas que se duplican sistema tras sistema.
  • Reducción de tiempo de desarrollo, en base a la generación de código automático, lo cual a su vez reduce el número de hora extras a desarrollar por un sistema.

Propuesta


Se realiza la siguiente propuesta de solución:

  • Es necesario detectar las características (features) comunes a un sistema, y las posibles variaciones de dichas características.
  • El análisis de dichas características detectadas y sus posibles variaciones, serán incorporados dentro de un generador de código, llamado Generador de características.
  • Los generadores de características serán los encargados de crear el código fuente que implementan las mencionadas características en base a una configuración sobre su variabilidad.
  • Los generadores de características deben ser independientes unos de otros, aunque pueden tener una serie de interfaces con las que exponer servicios a otras características, con el menor acoplamiento posible (debe ser lo más independientes posible).
  • La configuración de la variabilidad debe ser lo más versátil posible, si en una primera versión se uso XML, se intentara usar Ruby como lenguaje de configuración, parecido a la configuración de los archivos RakeFile o a un archivo podFile de CocoaPods.
  • Igualmente la generación de un sistema se llevara a cabo mediante la agrupación de varios generadores de características, que interactúan entre sí, para crear el código de dicho sistema.
  • La configuración, tanto del sistema, como de la variabilidad del sistema deben hacerse a través de una interfaz grafica que facilite dicha tarea.
  • Cuando se genera el código de un sistema, es necesario considerar que el sistema no puede generarse en un 100% de forma automática, por lo que habrá una parte del sistema que será creada automáticamente, y otra parte que lo creara el programador. Es importante que el generador reconozca la parte creada manualmente por el codificador y no sea reemplazado su código en ninguna circunstancia.
  • La creación de generadores de características en sí, es construida de forma manual, y se crean en parte a base de plantillas de código y analizadores de código, realizados en Ruby
  • Estos generadores de características una vez creados, podrán ser usados por varios programadores, con lo que se creara un repositorio centralizado en los que los programadores puedan subir sus generadores de características, o bajar los generadores de característica creados por otros programadores, algo parecido a las gemas de Ruby.
  • Hay que considerar que el generador de características, genera código, esa es su funcionalidad, es decir en ningún caso son librerías o framework a usar en nuestro código, sin embargo el código generador si puede usar librerías o framework externos.
  • Unos de los objetivos de generar el código, es aumentar la calidad del sistema, haciendo que el código generador implemente patrones de software, así como estándares y mejores prácticas de programación.
  • Hay que considerar que si tenemos un sistema generado con una versión de un generador de características y descargamos una nueva versión de las características podemos volver a generar el código y aprovechar las nuevas mejoras y cambios de esta versión.

martes, 1 de diciembre de 2015

Regla N°10 de la Ingeniería de Software: Si no es sencillo está mal hecho


El desarrollo de un software tiende a complicarse… a complicarse mucho. Se complica sacar el proyecto a tiempo, se complica las relaciones con el equipo de trabajo, con los proveedores o con los recursos. Debemos mantener esa complejidad bajo control, teniendo en la mente que todo lo que hagamos cumplir la regla "Si no es sencillo, está mal hecho".

La sencillez muchas veces se confunde. Sencillez no quiere decir fácil, es casi siempre lo contrario. Es difícil hacer las cosas sencillas. Casi siempre invertir en sencillez es un proceso costoso al principio y ventajoso al final del proyecto. El objetivo de esta regla es conseguir sistemas que estén guiados por la sencillez.

Para considerar un sistema sencillo debe cumplir las siguientes características:

  • Sencillo de entender.
  • Sencillo de explicar.
  • Sencillo de mantener.


Algunos consejos para conseguir sencillez son los siguientes:

  • Usa programación orienta a objetos: No veas un sistema como un flujo que va desde un punto ‘A’ a un punto ‘B’, sino como entidades que se relaciones entre ellas, e intercambian información.
  • Cada vez que uses una sentencia if, preguntante si no está organizando el código para evitar usar herencia (donde cada parte de if y el else debiera ser una clases hija con determinadas características).
  • Usa patrones de software: Son formas comprobadas de resolver determinados problemas, son extensamente conocidos, y son válidos tanto para incorporarlos en nuestros sistemas, como campo de estudio acerca de su sencillez.
  • Vuelvo a hacer: La primera vez que resolvemos un problema posiblemente no sea de la forma más sencilla posible, sin embargo ya tendremos una imagen clara del problema, si no estamos convenidos que la solución es lo suficientemente sencilla, es mejor rehacerla con la experiencia que ya tenemos. El problema de la complejidad es que crece como una bola de nieve, por eso es mejor rehacer partes de las que no estamos seguros de su sencillez.
  • Enfócate en hacer módulos que hagan muy pocas cosas pero que lo hagan muy bien.
  • Reúsa código: Casi todos los entornos y lenguajes de programación, como Java, Ruby o .NET, tienen repositorios de librerías, muchas excelentes, que resuelven muchas problemas comunes. Es bueno conocerlas y usarlas.
  • Pero no hagas tu código dependiente de librerías externas, encapsula apropiadamente las librerías para sea sencillo su reemplazo en caso que sea necesario.
  • Hablando de patrones, usa el patrón fascade (fachada), dicho patrón encapsula en funcionamiento de sistemas complicados, exponiéndolos con una interfaz mucha más sencilla. Este patrón es extremadamente útil cuando nos comunicamos con sistemas viejos, librerías en otros lenguajes o simplemente con elementos que no son sencillos, ni claros, pero no podemos modificarlos, ya sea porque no tenemos el código fuente, o porque se sale del ámbito de nuestro desarrollo. El patrón fascade lo expondrá para nosotros de una forma sencilla, y la complejidad del código a consumir no será contagiada a nuestro código.
  • Haz sistemas que no dependan de la implementación interna de otros sistemas (o módulos): Los sistemas se comunican por interfaces definidas, pero dichas interfaces debe ser independiente de sus respectivas implementaciones, es decir se debe poder cambiar la implementación sin afectar a las interfaces, ni a los sistemas con los que se consumen.


miércoles, 28 de octubre de 2015

Cuestión de confianza III: ¿Dónde están los malos?

Los “malos”, son personas individuales, o mafias que se dedican a buscar sujetos o entidades vulnerabilidades para poder obtener nuestros datos personales o financieros, con intención de lucrase con ellos. En algunos caso puede que no exista lucro, solo existe el afán de hacer daño, de perjudicar o de exponer información de nuestra vida que nos hacen sensibles a ataques futuros, como datos sobre nuestra salud, dinero o familia.

Ahora bien, ¿Dónde están los malos?

Hay una reglar sencilla para tener claro que elementos debemos proteger, por que allí están los intrusos. La regla es:

¡¡¡Los malos están en todas partes!!!

  • Están del lado del Usuario: Pueden usar técnicas de ingeniería social, tener acceso a los medios de autentificar del usuario, o atacar directamente la computadora de la víctima.
  • Están en las comunicaciones: O bien analizándolas o falseándolas para que pensemos que estamos operando directamente con nuestros servidores o sitios web, cuando no es así.
  • Están en el servidor: Empleados que tiene acceso a información privada o secreta, y que solo se confía en su "buena" fe para que no usen sus privilegios de forma maliciosa o bien software pernicioso que explota la información directamente de los servidores bancarios.
  • Están en lo servidores adicionales: Además de lo mencionado anteriormente, es posible que aplique solo la seguridad en los puntos de entrada de la red, y se deje toda una intranet desprotegida, confiando en que estamos protegidos de ataques del exterior. La seguridad se debe incluir en cada uno de los elementos de nuestra infraestructura.

miércoles, 21 de octubre de 2015

Cuestión de confianza II: Factores de autentificación.


La autentificación es una de las partes más delicadas de implementar en un sistema, básicamente consiste en asegúranos que la persona que se contacta a nuestro sistema es quien dice ser, pero no solo eso sino que los usuarios puedan garantizar que se están conectando a nuestro sistemas y no a ningún otro que se haga pasar por este.

Acerca de los factores de autentificación


Los factores de autentificación son maneras de clasificar los métodos posibles en los que basar la autentificación a nuestros sistemas.

  • Factor 0: Algo la empresa que ofrece el servicio conoce y el usuario debiera conocer. Se aplica, por ejemplo, haciendo preguntas por teléfono, en el que el operador telefónico conoce las preguntas (mediante un script), pero no las repuestas (o por lo menos no todas, porque su veracidad debe ser resulta por el  sistema informático). Es importante que el usuario sea el que inicie la comunicación telefónica siempre y en ningún caso contestar preguntas cuando es el usuario el que recibe la llamada del teléfono, puesto que no sabemos quién nos está llamando realmente, lo cual podría ser un fraude para conseguir nuestros datos personales. En lo general conviene evitar este tipo de autentificación, aunque generalmente no es posible porque necesitamos una atención personalidad.
  • Factor 1: Algo que el usuario conoce y que proporciona para acceder a su servicios, es esta categoría entran los password y los NIP, que deben estas compuestos con una fortaleza mínima, y que idealmente no conoce la institución, pero conoce los medios posibles de validarlo (por ejemplo con password encriptados no reversible, como SHA512).
  • Factor 2: Contraseñas dinámicas generadas por medios electrónicos, aquí entra el papel de los Token,  los cuales son dispositivos hardware (o aplicaciones moviles) que en base al tiempo, generan  un número (exclusivo para el usuario) que sirve para que autorice una operación en el sistema (y solo una), una vez que la ha autorizado, necesitara un nuevo número de token, para nuevas operaciones. Esto es "Algo que tiene el usuario", en este caso el dispositivo físico
  • Factor 3: Medios biométricos (“Algo que el usuario es”), Alguna característica física propia del cliente en si, como su huella dactilar, o patrones en la retina, etc.

Lo recomendable es usar un doble factor de autentificación. Combinamos un factor de seguridad, junto con otro, lo más común es combinar el factor 1 (contraseña), con el factor 2 (token).

De esta forma aunque alguien se adueñe de nuestras contraseñas, será incapaz de realizar ninguna operación en nuestro sistema por no poseer el número de token que le da acceso.

Todo esto en la práctica: Ejemplo con Gmail



Google ofrece un sistema de autentificación en dos pasos, que consiste de un sistema en el uso de la contraseña del usuario de una cuenta de Google, y adicionalmente un Token, que puede ser un token  basado en el tiempo o basado o un Token SMS.

Se activa desde la configuración de GMAIL



Se activa mediante un Token SMS que llega al celular registrado


Una vez autentificados nos pedirá que indiquemos la pantalla


Y mediante la lectura de un QR, queda instalada la clave simétrica en un celular



Desde este momento podremos usar la autentificación en dos pasos:



Ventajas de este token:

  • Es gratis
  • Se basa en estándares y algoritmos públicos

Desventajas:

  • Está pensado para los productos de Google, o aquellos que usan sus servicios.

jueves, 8 de octubre de 2015

Cuestión de confianza I: Criptografía


Es curioso como casi todos los elementos en los que se basa en internet se crearon de una manera más o menos insegura en la que cada elemento viajaba por la red si ningún tipo de protección, libres para que cualquiera pudiera leer su contenido. Esto fue así, hasta que entro en juego la criptografía.

Muchas veces la gente no es consciente de la información personal, privada y secreta que viaja a través de sus computadoras o celular, o si lo es no le da importancia requerida. El tema es que es realmente importancia limitar el acceso a nuestra información, porque nunca sabemos que consecuencia podría tener que un extraño acceda a nuestro teléfono, nuestras fotos o mensajes, lo que para nosotros es inofensivo para otras personas abren posibilidades de extorsión o estafas en contra nuestra.

La criptografía garantica que solo nosotros (u otras personas autorizas) puedan acceder a nuestra información, de forma que sepamos que lo que sale de nuestros dispositivos, está debidamente protegida, y es confidencial.

La criptografía es un conjunto de técnicas y métodos en que los que un mensaje origen (o en claro) con información confidencial, se convierte en otro sin aparente significado y que puede viajar por medios no seguros, con la tranquilidad de que el mensaje original no podrá ser descubierto, sin aplicar los correspondiente métodos criptográficos sobre el mensaje original.

La criptografía existe desde hace muchos siglos, siempre asociada al envió de mensaje secretos entre dos partes. Algunos sistema de criptografía antiguos, se basan en la ocultación del método criptográfico. En los sistemas criptográficos modernos, el método de inscripción es público (o podría serlo sin comprometer la seguridad) y al mismo tiempo poseen una clave de encripción que debe ser secreta, y que si la cual aunque tengamos el algoritmo y el mensaje cifrado, no conseguiremos tener el mensaje original.

Una excepción al tema de claves de encripción son los algoritmos de hash donde la información se encripta de forma no reversible, sin necesidad de una clave o llave de encripción, en una cadena de longitud fija tal que así:

Original: “ESTE ES MI PASSWORD”

Este es el hash creado: ed85e76ecad699fdb1bfa36876f35e665a3105750f0af9c4d6bbfc80a3b664a1

Debido a que es imposible partir del hash y llegar al original, Esta es la forma ideal para almacenar password, ya que incluso cuando la base de datos de los usuarios se viera comprometida (por ejemplo que se robara) no supondría un problema, porque no se podrían averiguar los password.

Al margen la autentificación anterior, se dan principalmente dos tipos de criptográfica.

Criptografía simétrica


Tanto el recepto del mensaje encriptado, como la persona que encripta, usan la misma clave de encripción para realizar sus operaciones. Algoritmos que lo usa son por ejemplo AES (Rijndael).

Las ventajas de este método son:
  • Es la practica tiene una velocidad aceptable
  • Es muy seguro

Las desventajas:
  • La principal desventaja es que un usuario genera la clave y tiene que pasársela a otro usuario, lo cual podría comprometer la conexión desde un inicio

El hecho que compartan la misma clave, es un problema, el único que tiene este tipo de criptográfica, porque ¿Cómo se hace que el usuario final y destino tengan la misma clave?, solo enviando la clave por un medio que sea seguro, para garantizar que nadie más la tiene, pero precisamente necesito intercambiar la llave porque no tengo un medio seguro para enviar información.

Criptografía asimétrica


Consta de dos claves, en lugar de una, llamadas clave privada y clave pública, la clave pública sirve para encriptar, y es de libre acceso, la clave privada para desencriptar y solo la tiene una persona (la que genero las claves). Además la privada sirve para firmar mensajes y garantizar que la persona que la usa es el dueño de la clave.

En la práctica funciona así: Una persona genera (a través de un algoritmo) una clave privada y pública (que se complementan entre sí), se queda para si la clave privada, y distribuye la clave pública (a quien desee), a partir de ese momento, quien desee mandarle un mensaje encriptado, puede hacerlo usando la clave pública, y solo el podrá desencintarlo usando la clave privada. Igualmente si él quiere mandar un comunicado y garantizar su autenticidad, podrá firmarlo con su llave privada, y todo aquel que tenga la llave publica, podrá validar su origen.

Algoritmos que implementan esta tecnología son por ejemplo RSA o DSA.

Las ventajas de estos algoritmos son:
  • Seguridad en cuanto al custodio de las claves (nunca se difunde la clave privada)
  • Seguro en cuanto los mecanismo de inscripción

Las desventajas:
  • Increíblemente lento

En esta criptografía se resuelve el problema de la llave compartida, puesto que al haber dos llaves, se puede distribuir libremente la llave pública (a cualquier persona) para encriptar, y la permanecer debidamente custodiada la llave privada para desencriptar. Así por ejemplo dos personas (o entes), pueden iniciar una comunicación segura, simplemente intercambiando sus llaves públicas y usando sus llaves privadas para desencriptar.

Debido a que la criptografía asimétrica es realmente lenta, en lugar de encriptar un mensaje completo, se genera una llave simétrica aleatoria, con la que se encripta el mensaje y se envía el mensaje encriptado y adjunto con la llave simétrica encriptada (ahora sí) con la llave asimétrica publica, lo cual garantiza la velocidad y la confidencialidad.

Certificados digital


Cuando recibimos un mensaje firmado con una llave privada, podemos validar su autenticidad con nuestra llave pública. Esto quiere decir que podemos garantizar que la persona que tiene la llave privada es la se está comunicado, con nosotros, puesto que debe coincidir con la llave publica que nos proporcionó.

Hay que agregar que la firma es diferente por cada mensajes, por lo que garantiza no solo que el mensaje fue enviado por quien tiene la llave privada, sino además que el mensaje no ha sido modificado en el cambio.

Un detalle importante es que solo garantiza eso, es decir que el mensaje fue firmado con la llave privada, pero no garantiza que esa firma electrónica pertenezca a una persona en particular. La firma podría ser de cualquier persona, y haberse generado en cualquier momento.

Para garantizar además que la firma privada pertenece a una determinada persona o entidad, se usan los certificados, que bien pueden identificar a una persona o a un ente como una empresa o un banco.

Pero, ¿En que consiste exactamente un certificado? Imaginemos que yo quiero comunicarme (a través de una computadora) con otra persona o entidad, por ejemplo una tienda. Con el uso de llaves públicas (y privada) garantizo que la comunicación es confidencial entre ambos, pero de ninguna forma garantizo que esa llave pertenezca a la tienda, pero igualmente imaginemos que existe un tercer elemento, un ente en el que confiamos los dos (la tienda y el usuario), que garantice que esa llave privada pertenece a la tienda, ¿Cómo lo puede hacer? Dando por supuesto que yo confió en el tercero, que se llama entidad certificadora, esta firma (con su propia llave privada), la llave publica y demás información de la tienda, posterior a que valide la identidad de la tienda (mediante documentos, escrituras, registros de empresa, visitas en persona). En este punto ya tenemos un certificado, que contiene la llave pública, y que está firmado por alguien en el que confiamos que ha validado correctamente la identidad de la tienda, de esta forma queda ligada la identidad con la llave pública.

¿Quién son esas entidades certificadoras y por qué confiamos en ella? Son grandes empresas cuyo servicio es precisamente ese garantizar la identidad de entes y personas, y son aceptadas a nivel mundial como VERISIGN, o incluso gobiernos o entidades gubernamentales que realizan dicha función.

¿Cuál es proceso para generar un certificado?

  1. Se genera un par de llaves (pública y privada)
  2. Se realiza una petición de generación de certificado en base a la clave pública, y a los datos de la empresa (y los host que queremos certificar).
  3. Se envía la petición a una entidad certificara, que realizara los pasos necesarios para garantizar que somos la empresa para la cual estamos pidiendo los certificados, y una vez garantizado nos expedida dicho certificado.
  4. En nuestro servidor podemos unir la llave privada con el certificado, y en base a eso configurar nuestros servidores para que lo usen apropiadamente

Nuestro clientes al conectarse a nuestros servidores descargaran el certificado (con la llave publica), y al estar firmado por la entidad certificadora (en la confiamos), asumiremos que el servidor al que nos estamos conectando es el correcto. Igualmente si no está firmado o lo está por alguien en que no confiamos seremos advertidos de esta situación, y estará en nuestra decisión continuar la comunicación con dicho servidor.

¿Qué ocurre cuando queremos generar un certificador de pruebas?


Es posible que los certificados se firmen a sí mismos, como si fueran una entidad certificadora, estos se llaman certificados autofirmados.

Por otro lado es posible que firmemos un certificado a través de otro certificado, por ejemplo puedo firmar todos los certificados internos de una empresa, con un mismo certificado, y configurar en los ordenadores de la empresa, el certificado firmante como entidad firmante de confianza. A partir de este momento todos los certificados firmados con aquel, serán de confianza.

domingo, 20 de septiembre de 2015

Swift: Variables, Opcionales (?), Opcionales Implícitamente Desempaquetados (!) y conversiones entre ellas (as, as? y as!)


!?

Actualmente me encuentro aprendiendo Swift para programar dispositivos iOS,  es un lenguaje con características muy atractivas que me está agradando mucho.  Me gusta sobretodo la seguridad que ofrece al ser muy restricción en las opciones que ofrece para programar algunos aspectos. Cuanto mas restrictivo sea el lenguaje mas seguro será. Algunos programadores sienten que un lenguaje restrictivo cohíbe su libertad al momento de programar, yo creo que confunde el concepto de libertad, libertad es poder jugar con tu hijo por la tardes, en lugar de estar en la madrugada con una sobredosis de café (o de Red Bull), preguntándote porque está mal referenciado un puntero.

Pero antes de nada, ¿Cómo pruebo Swift?


- Es muy fácil, solo necesitas ejecutar XCode en tu Mac y …

- No tengo una Mac

Vale, entonces está más complicado,  se supone que la versión 2.0 de Swift, va a ser libre, lo cual podría implicar ver el lenguaje en otras plataformas como Windows o Linux, pero hasta entonces necesitaríamos una Mac. Existen algunas alternativas, como por ejemplo este compilador en línea para probar pequeños script de Swift e ir acostumbrándonos al lenguaje:


o este


¿Listo? Sigamos entonces…


Unas de las cosas que más me costado comprender son las variables opcionales, sobre todo por su aparente parecido con los tipos de datos Nulleables de C#, por que manejan conceptos parecidos al igual que su sintaxis. Hasta que no comprendí que son cosas completamente diferentes, no entendí el uso de los opcionales. (Así que aunque suene igual, ni los compares, no se parecen en nada).

Variables en Swift


Una característica de las variables en Swift, es que siempre deben tener valor, o más bien siempre deben estar instanciadas, no pueden tener un valor nulo, o nil, como se les llama en Swift.

Esto quiere decir de que cualquier variable que tengamos definida, sea cual sea, siempre tendremos acceso a sus métodos y propiedades, si necesidad de realizar una validación previa.

Por ejemplo si tuviéramos un String declarado, la cadena siempre debiera tener un valor y nunca podría valer nulo, si no inicializamos la cadena el programa simplemente no compilara. En el caso de definiciones de clases, la variables propiedades de esta deben ser obligatoriamente instanciadas en al momento de su declaración o en el constructor del objeto.

El siguiente código es válido, y el método endIndex, siempre estar disponible por que strValor siempre tendrá un “valor”.

var strValor = "Hola"
println(strValor.endIndex)

También el siguiente código es válido:

var strValor:String 
strValor = "Hola" 
println(strValor.endIndex)

El siguiente código directamente no compilara por querer usar la variable antes asignarla un valor (nótese que no dará un error en tiempo de ejecución, sino que simplemente no compilara).

var strValor:String 
println(strValor.endIndex)

El resultado de la compilación será:
 
error: variable 'strValor' used before being initialized

Tampoco es posible asignarle nil (nulo) a la variable, igualmente no compilara. El siguiente código no será valido:

var strValor:String 
strValor = nil 
println(strValor.endIndex)

Siendo el error el siguiente:

error: cannot assign a value of type 'nil' to a value of type 'String' strValor=nil

Variables Opcionales en Swift


Ahora bien y ¿si realmente necesitamos que algunas variables valgan nulo?, es posible que la ausencia de valor tenga un significativo para nosotros, o que directamente no podemos asignar un valor iniciar a nuestras variables. Para lo cual existen los opcionales.

Los opcionales son variables que pueden tener un valor de un determinado tipo o valer nulo. Para crear un opcional de un determinado tipo simplemente agregamos el símbolo ? al tipo, por ejemplo para tener un opcional de String, lo declaramos como String?:

var strValor1:String? 
strValor1="Hola" 
strValor2=nil

Las dos asignaciones anteriores son validas.

Podemos comprobar si el valor asignado es nulo, simplemente preguntándolo con un if, igual que lo haríamos en otros lenguajes:

if strValor1==nil 
    println ("Es NULO") 
}

Sin embargo si queremos usar el valor del opcional debemos realizar un proceso llamado desempaquetamiento, esto consiste en que obtengamos el tipo inherente al opcional, por ejemplo de un opcional de String, el tipo inherente seria el mismo String.

Para desempaquetar un opcional, podemos usar el operador ! o el operador ?, a la derecha de la variable. Cada operador tiene una funcionalidad diferente.

El operador ? indica al compilador que intente desempaquetar la variable y de no poder no continúe la operación con la variable opcional, asignando nil al resultado requerido (si se requiere).  Por ejemplo:

var strValor1:String?
strValor1 = nil
println (strValor1?.endIndex)

Por ejemplo se mostrara en la pantalla nulo (nil), como resultado, pero no fallara

Otra curiosidad del uso del operador ?, es que siempre devuelve un opcional, del tipo esperado, por ejemplo, el tipo esperado para el método endIndex, es un Integer así que devolvería un Integer?, esto es porque el compilador requiere saber siempre con el tipo que se está trabajando (Swift es de tipeado fuerte, con lo que la única manera de estar seguro del tipo al momento de trabajar es trabajar siempre con opcionales Cuando se usa el operador ? , por ejemplo la ejecución del siguiente código:

var strValor1:String?
strValor1 = "hola"
println ("la variable mide  \(strValor1?.endIndex)'")


Dara el siguiente resultado:

la variable mide 'Optional(4)'


El operador ! permite desempaquetar el valor de opcional,  el valor debe existe y en caso de no existir provocara un error, por lo tanto solo debemos ejecutarlo solo en el caso que estemos seguro que el opcional tenga un valor:

var strValor1:String?
strValor1=”Hola”
println(strValor1!.endIndex)

El siguiente código por ejemplo dará un error en tiempo de ejecución al no tener valor el opcional (es nulo puesto que nunca se inicializo)

var strValor1:String?
println(strValor1!.endIndex)

Esto nos supone un problema, puesto que al usar opcional, debemos comprobar siempre antes de usarlos que tengan valores y desempaquetar el valor en cada uso, por ejemplo en el caso del string debiera ser así:

var strValor1:String?
strValor1 = "Hola"
if (strValor1 != nil)
{
    println("Letras \(strValor1!.endIndex)")
    println("Primera letra \(Array(strValor1!)[0])")
    println("Mayusculas \(strValor1!.uppercaseString)")
    println("Minusculas posicion \(strValor1!.uppercaseString)")
}
else 
{
    //Lo que sea
}

El resultado es el siguiente:

Letras 4
Primera letra H
Mayusculas HOLA
Minusculas posicion HOLA

Como vemos cada vez que queremos usar la variable tenemos que desempaquetarla con el operador ! , Swift nos propone la estructura if let, para prevenir realizar este desempaquetado en cada ocasión y que nuestro código quede más comprensible:

var strValor1:String?
strValor1 = "Hola"

if let strValorDesenpacado=strValor1
{
    println("Letras \(strValorDesenpacado.endIndex)")
    println("Primera letra \(Array(strValorDesenpacado)[0])")
    println("Mayusculas \(strValorDesenpacado.uppercaseString)")
    println("Minusculas posicion \(strValorDesenpacado.uppercaseString)")
}else {

    //Lo que sea

}


Aunque pudiera parecer lo contrario la expresión if let, es una expresión completa y no dos por separado (no es un if mas un let). Al detectar el compilar la orden if let, lo que él entiende es “Desempaqueta la variable de la derecha, si puedes hacerlo (es diferente de nil), asígnaselo a la variable de la izquierda y ejecuta el código del if.”


Opcionales Implícitamente Desempaquetados


Los opcionales implícitamente desempaquetados (Implicitly Unwrapped Optionals, a partir de ahora por sencillez solo opcionales implícitos), son una vuelta de tuerca más al tema de los opcionales, son los más parecidos a los variables por referencia de otros lenguajes como .NET o Java, las variables pueden ser nulas o tener un valor, pero no necesitan ser desempaquetadas en ningún caso, se usan sin los operadores ¿ o ! ( de allí la parte implícita), pero si intentamos usar una variable con un valor nulo, esta generada un error:

var srtValor:String!
srtValor="Hola Mundo"
println(srtValor)

//Notese que no es necesario desempacar la varible
println (srtValor.endIndex)
srtValor=nil
//La siguiente instruccion fallara pero se compilara correctamente
println (srtValor.endIndex)

El uso de los Opcional Explícitos entre, otros motivos, es la interoperabilidad con ObjetiveC, donde es más natural trabajar con variables que se comportan de esta forma (pueden tener valor  o ser nulas). Cuando tengamos que interactuar con la API de ObjetiveC (lo cual pasara mucho), sobre todo para recibir valores de esta, casi siempre serán un opcional implícito.

Conversiones de tipo mediante as, as? y as!


El conjunto de operadores as, nos ayudan a convertir objetos de un tipo en objetos de otro, a través de mecamismo de empaquetado/desempaquetado o de hererencia. Para nuestros ejemplos, vamos a contar con tres clases ClaseA, ClaseB , siendo que ClaseB hereda de ClaseA:

class ClaseA
{
    let Mensaje="Hola Mundo"
}

class ClaseB : ClaseA
{

}

Operador as


Usaremos el operador as, cuando el compilador pueda garantizar que la conversión (o cast) es posible, en tiempo de compilación, y que esta siempre es posible, aunque agreguemos mas código en un futuro (no basta con que nosotros como codificaciones estemos seguros, el compilador debe estar seguro al 100% ). Por ejemplo,  es posible convertir una variable de tipo ClaseB en una de ClaseA o en opcional de ClaseA, mediante el operador as, por que el compilador sabe que dicha conversión es posible siempre:

var claValor: ClaseB = ClaseB()

//Conversiones
var clbValor1 =  claValor as ClaseA
println ("El tipo es '\(clbValor1.dynamicType)'")

//Conversiones
var clbValor2 =  claValor as ClaseA?
println ("El tipo es '\(clbValor2.dynamicType)'")

La salida sera:

El tipo es 'main.ClaseB'
El tipo es 'Swift.Optional'

Pero sin embargo no sera posible usar el operador as para convertir una variable de tipo ClaseA en una de tipo ClaseB, por que el compilador no puede garantizar que siempre sea posible, puesto que no todas los clases que hereden de ClaseA son forzosamente de tipo ClaseB, esto se aplica aunque en el código se vea claramente (por una persona)  que la variable si es convertible.

En el siguiente ejemplo fuerzo la conversion de una variable de tipo ClaseA en una de ClaseB (downcasting):

var claValor1: ClaseA = ClaseB()
//Conversiones
var clbValor1 =  claValor1 as! ClaseB
println ("El tipo es '\(clbValor1.dynamicType)'")

El los siguientes ejemplos, convierto la variable opcional de tipo ClaseA, en una de tipo ClaseB (no opcional) y una Opcional de ClaseB:

var claValor2: ClaseA? = ClaseB()
//Conversiones
var clbValor2 =  claValor2 as! ClaseB
println ("El tipo es '\(clbValor2.dynamicType)'")
var clbValor3 =  claValor2 as! ClaseB?
println ("El tipo es '\(clbValor3.dynamicType)'")

Ahora bien que pasaría en el ejemplo anterior, si la variable opcional del ClaseA valiera nulo y quisiera hacer el casting igualmente a una de ClaseB no opcional:

var claValor2: ClaseA? = nil
//Conversiones
var clbValor2 =  claValor2 as! ClaseB
println ("El tipo es '\(clbValor2.dynamicType)'")

var claValor: ClaseA = ClaseB()

//Conversiones
var clbValor =  claValor as ClaseB

El error marcado sera el siguiente:

error: 'ClaseA' is not convertible to 'ClaseB'; did you mean to use 'as!' to force downcast?

¿Por qué si visualmente se ve que se puede hacer un cast, el compilador no nos deja?, bueno, esto es porque en un futuro podríamos hacer asignar otro valor a la variable claValor, e impedir el cast, Swift nos protege de estos posible futuros errores, el siguiente código seria incorrecto y tampoco compilara (incluso visualmente):

var claValor: ClaseA = ClaseB()
claValor = ClaseA()

//Conversiones
var clbValor =  claValor as ClaseB

Operador as!


El operador as!, nos permite forzar el cast, cuando estemos seguros que el posible realizarlo (aunque el compilador no lo este), es una manera de decir al compilador, que nosotros asumimos la responsabilidad sobre posibles fallos del cast. Los siguientes cast son posibles:

var claValor2: ClaseA? = ClaseB()
//Conversiones
var clbValor2 =  claValor2 as! ClaseB
println ("El tipo es '\(clbValor2.dynamicType)'")
var clbValor3 =  claValor2 as! ClaseB?
println ("El tipo es '\(clbValor3.dynamicType)'")

Ahora bien si no es posible el cast, la conversión fallara y fallara en tiempo de ejecución (no en tiempo de compilación), por ejemplo en el siguiente código:

var claValor2: ClaseA = ClaseA()
//Conversiones
var clbValor2 =  claValor2 as! ClaseB

El operador as?


El operador as?, nos devuelve siempre un Opcional del tipo destino de la conversion, por ejemplo si el destino es un string, el resultado siempre sera un string?.

Se usa este operador para realizar cast de los cuales no estamos seguros que sean posible realizarlos, pero no queremos que falle en tiempo de ejecución. Si es posible realizar el cast se nos devolvera un opcional del tipo destino, si no es posible el resultado sera un nulo, por ejemplo:

//Conversiones
var clbValor2 =  claValor2 as? ClaseB
println ("El tipo es '\(clbValor2.dynamicType)'")

Devolvera un opcional de ClaseB (ClaseB?)

Debemos comprobar antes de usarlo si es valor devuelto es nulo, y si no es nulo desempacarlo para obtener, ahora si, un elemento de tipo ClaseB:

var claValor2: ClaseA = ClaseB()

//Conversiones
var clbValor2 =  claValor2 as? ClaseB

if clbValor2 != nil
{
    let cblValor3 = clbValor2!
    println ("El mensaje es '\(cblValor3.Mensaje)'")

}else {

    println ("El objeto no se puede convertir")

}

Es posible simplificar este conjunto de llamadas usando la instrucción if let revisada anteriormente:

var claValor2: ClaseA = ClaseB()

if let clbValor2 = claValor2 as? ClaseB
{
    println ("El mensaje es '\(cblValor3.Mensaje)'")

}else {

    println ("El objeto no se puede convertir")

}

La seccion del if solo se ejecuara si es posible la conversion, y se trabajara dentro del if con el objeto desempaquetado, sin necesidad de realizar ningún otro proceso adicional, la parte del else se lenzara cuando la conversión no haya sido posible.

Y esto es todo


¿Qué futuro tiene Swift?, es dificil saberlo y posiblemente vendra marcado con la salida de Swift 2.0 y si es capas de ofrecer una mayor integracion con XCode (en el cual hace cosas extrañas a veces), igualmente seria interesante ver Swift funcionando en otras plataformas no Mac. Quedamos en espera de observar que pasa en los siguientes meses.

domingo, 6 de septiembre de 2015

Un año después

¡Cumplimos un año en el blog!, el primer post fue el día lunes, 25 de agosto de 2014, así que unas semanas tarde del primer aniversario, decidí hacer un pequeño resumen de lo acontecido hasta ahora.



¿Cuántas publicaciones hemos hecho hasta ahora?, unas 21, una y media por mes aproximadamente, que no es un gran número, pero este es un proyecto individual y muy personal, en el cual cada publicación intenta reflejar un poco de mi vida laboral, mi experiencia, y acercar un poco a los posibles interesados al día a día de la ingeniería de software.

En general estoy contento con las publicaciones de este año y esperemos continuar con un ritmo parecido o superior (si es posible) el año que viene.

Podemos clasificar lo ocurrido en este año de la siguiente forma:

¡Tenemos redes sociales!


Estamos en Facebook y en Google+ en los siguientes enlaces:


Post relativos a reglas de software de la ingeniería de software


Es un conjunto de reglas o recomendaciones que nos ayudan a diseñar y construir software, con la intención de que aumentar nuestras posibilidades de éxito. Se han publicado las siguientes:


Post de diversos temas



Investigación en ingeniería de software


Los siguientes post están relacionados a prácticas y documentos realizados en el master que me encuentro actualmente estudiando en la UNED, “Investigación en Ingeniera de Software”, y el cual espero acabar en el algún momento de este siglo o el siguiente.


Y esto es todo en el primer año, espero que os haya gustado :-)