jueves, 13 de abril de 2017

Referencias Culturales: Inyección de código en Rick y Morty


La inyección de código es una vulnerabilidad, por la cual un atacante consigue ejecutar un código malicioso en nuestro sistema, introduciéndolo, generalmente, a través de una entrada de datos de dicho sistema.

En el primer capítulo de Rick y Morty de la tercera temporada ( Rick & Morty - S03E01 - Rickson Break ), se ve claramente un ejemplo Inyección de código, con fatales consecuencias (para los enemigos de Rick).



Rick y Morty, es una serie de animación para adultos de Adult Swim, en la que un joven y su abuelo inventor viven aventuras a través de distintos lugares y dimensiones. En este capítulo Rick fue capturado y le están haciendo una exploración dentro de su mente (a través de sus recuerdos), para recuperar cierta información que quieren obtener sobre uno de sus inventos.

En la escena ocurre algo parecido un escalamiento de privilegios, hasta ser root , por no validar los datos de una entrada. Veamos la parte de la inyección de código en cuestión:






Bola extra. Otro ejemplo de inyección de código en Rick y Morty.

En el capítulo cuarto de la primera temporada (Rick & Morty - S01E04 - M. Night Shaym-Aliens ! ), hay una escena parecida de inyección de código, en la esta vez se intenta obtener información sobre un combustible creado por Rick. Rick es puesto en una simulación holográfica, e intentando escapar de ella acaba creando el combustible, los enemigos de Rick intentan recrear la formula sin antes hacer algún tipo de comprobación. La moraleja es “Cualquier entrada es siempre maliciosa, valida tus datos”.




lunes, 3 de abril de 2017

Diferencias entre Ciencias la Computación, Ingeniera y Arquitectura de Software


Para referirnos a nuestra profesión (o a aspectos de ella) de una forma más o menos formal, solemos usar términos como “Ciencias de la computación”, “Ingeniería de Software” o “Arquitectura de Software”, muchas veces de manera intercambiada, y sin distinguir entre cada uno de ellos. En el siguiente artículo voy a establecer puntos que nos ayuden a diferenciarlos entre sí.

Dejemos claro para comenzar que el objetivo de nuestra profesión es hacer sistemas software. Ese es el punto que no debemos perder de vista, y debemos enfocarlo todo a través de él.

¿Qué es un sistema?


Un sistema, para la finalidad que nos ocupa, es un conjunto de elementos, de diversa índole, que trabajan juntos para poder conseguir un objetivo.

¿Qué es un sistema software?


Es un conjunto de elementos (principalmente) software y de otra índole que interactúan entre sí para ofrecer una funcionalidad.

En cuento al software puede incluirse aplicaciones, servicios, portales web, programas propios o desarrollo de terceros.

¿Incluye los sistemas software, la parte hardware? Si. Es imposible ver un sistema software como algo aislado del hardware. El software está diseñado para instalarse en determinado hardware (Teléfonos, PC, MAC, servidores…) y en determinada estructura (como ciertas redes, o arquitecturas cliente servidor, o incluso modelos menos convencionales).

¿Los usuarios son parte del sistema? Si, en el sentido que estos cumplen roles que contempla el software. Es necesario diseñar siempre el software desde el punto de vista de las necesidades de los usuarios.

Ante de nada…


En cuento a las definiciones aquí expuestas, no son tratadas de forma académica, o dicho de otra forma no se busca empatar los conceptos con títulos universitarios ya que estos varían en cada país y muchas veces usan los términos equivalentes o casi equivalentes.

En este artículo se busca obtener en cada definición un fin práctico, casi laboral.

Arquitectura de Software


La arquitectura de software se encarga de la creación de sistemas, enfocándose en los puntos:

  • Formaliza el cómo se debe diseñar un sistema.
  • Define (identifica) los componentes de un sistema, las relaciones entre ellos y su funcionalidad.
  • Las conexiones con otros sistemas.
  • La escalabilidad y la capacidad de mantenimiento de un software.
  • La sencillez en general de un código.
  • Identifica los puntos reutilizables de un código, y crea un escenario donde esto es posible.

La importancia de una arquitectura es que garantiza que el código de un sistema siga siendo compatible “hacia atrás” (lo existen), y “hacia delante”, hacia las necesidades futuras y todavía no determinadas. En otras palabras posibilidad el cambio.

Ingeniera de Software


La Ingeniera del Software abarca más puntos y de índole más diversa que la Arquitectura de Software, o dicho de otra forma la Arquitectura de Software es un punto más, perteneciente a la Ingeniera de Software.

La Ingeniera de Software abarca todos los procesos de la creación de software, desde la identificación apropiada de las necesidades, hasta más allá de la creación de un sistema como producto ("más allá", porque la ingeniera de software no acaba con la entrega del mencionado sistema).

Los puntos en los que se enfoca la Ingeniera de Software son los siguientes:
  • Definir la metodología de trabajo. Dicha metodología puede varias según las necesidades del cliente, equipo (de trabajo), o producto.
  • Gestionar los proyectos, así como de los recursos asignados (que pueden ser humanos, físicos, o económicos)
  • Define apropiadamente todas las fases del proyecto, y las necesidades y objetivos de cada uno.
  • Define los roles a cumplir en el proyecto.
  • También se encarga de la relación (en varios niveles) con el cliente y de detectar sus necesidades.
  • Como ya mencionamos la arquitectura del software es gestionada como un subconjunto.
  • En general, define de manera formal todos los pasos de creación y mantenimiento de un sistema, abarcando no solo aspectos tecnológicos, sino de procesos y de gestión.

Ciencias de la computación


Las ciencias de la computación pertenecen a un rublo diferente a los anteriores, su fin es menos práctico y más teórico, enfocándose más a asuntos académicos y de investigación y menos en conseguir un producto funcional.

Las ciencias de la computación se encarga de descubrir que es lo “que se puede hacer” y “por qué”. La ingeniería se encarga de encontrar un sentido práctico, funcional e incluso laboral, al conociendo obtenido.


sábado, 18 de febrero de 2017

¿Qué es un framework?

Un framework es un conjunto de elementos que juntos nos ayudan a construir software de una manera más sencilla, de mayor calidad, y en menor tiempo. Podríamos decir que un framework se compone de las siguientes características:

Un objetivo limitado y concreto


El framework sirve para resolver una tarea perfectamente definida. Puede ser la distribución de las capas en nuestro sistema, facilitarnos la construcción de una capa en concreto, relacionar entidades de negocio con entidades de base de datos, o ayudarnos con otros aspectos como la inyección de código o semejantes.

Un conjunto de librerías


Un framework agrupa librerías diseñadas para solucionar la tarea para la cual está pensando. Dichas librerías están basadas en patrones de software y son consistente en todo el paquete (todos las objetos son creados y se usan de la misma forma). Además su funcionalidad es completamente extensible para resolver nuevas necesidades (sin modificar las librerías mismas).

Posiblemente un conjunto de herramientas


Aunque este punto podría estar incluido en el anterior, decidí hacer una división mas practicas. Las librería son los elementos que son referenciados desde nuestro código, la herramientas son aquellas que nos ayudan a crear nuestro código. Pueden ser que creen de forma automática todas las entidades de nuestro negocio o las entidades de nuestra base de datos, o las páginas web de nuestra aplicación. Los generadores de código automáticos entran en esta categoría.

Patrones de diseño


Los frameworks esta íntimamente relaciones con los patrones de diseño. Generalmente implementan una colección bastante común y amplia de ellos, y además obligan a que se sigan implementando dichos patrones en los sistemas donde son usando.

Metodología de trabajo


A la vez que el framework ofrece una colección de librerías para resolver un problema, también debe ofrecer una metodología de trabajo que nos indique como hacerlo. Solo hay una forma de hacer las cosas de forma "correcta" y esa es la forma es indicada por el mismo framework.

Si no se cumplen esta serie de características entonces no estaríamos hablando de un framework, sino simplemente de un conjunto de librerías reutilizables agrupadas.

domingo, 5 de febrero de 2017

Regla N°11 de la Ingeniería de Software: El primer código es para entender el problema, los restantes para hacerlo bien.


"En primavera de mi último curso en el instituto de Lisbon (o sea, en 1966) recibí un comentario manuscrito que cambió para siempre mi manera de enfocar las revisiones. Debajo de la firma del director, reproducida a máquina, figuraba a mano lo siguiente: «No es malo, pero está hinchado. Revisa la extensión. Fórmula: 2da versión = 1ra versión - 10%. Suerte.»", Mientras escribo, Stephen King, 2000.

Uno de los desafíos a los que nos enfrentamos los que nos dedicamos a crear sistemas software (de forma empresarial) es que debemos construir herramientas sobre ámbitos de negocio que no dominamos. Con lo cual nos enfrentamos a dos circunstancias:

  • Comprender los requisitos de un sistema.
  • Construir el sistema en sí.

En una metodólogia tradicional, tendremos el rol de analista, diseñador y codificador. El analista obtendrá los requisitos, el diseñador los convertirá en un modelo codificable, y el programador creara el código fuente. La posibilidad de que esos roles sean personas diferentes dependerá mucho de la empresa y de la situación en particular.

Como defensor del las metodologías agiles, creo que la mejor forma de comprender un problema es descomponiéndolo en problemas más sencillos y solucionándolos uno a uno.

Esto implica que hasta que no tengamos algo de código listo, no comprenderemos exactamente la necesidad que estamos intentando suplir. Es más, el ver la necesidad resulta, pueda cambiar los requisitos y la percepción sobre el problema real a tratar.

Los motivos anteriores hacen que el primer código no sea el más optimo, porque su objetivo está más orientado al análisis que a la implementación. La situación en este punto es tenemos un código que nos muestra una solución, pero es una solución temporal y estática (Si hubiera un cambio en los requisitos sería muy difícil de ajustar estar código para atenderlo).

Es por lo cual necesitamos realizar una segunda revisión del código, en estas caso ya no para resolver el problema de negocio, sino para asegurarnos que nuestro código sea de calidad, cumpliendo los siguientes requisitos:

  • Que no tenga código repetido.
  • Que se entienda claramente.
  • Que tenga los comentarios, que seguramente omitiste la primera vez.
  • Y el más importante, que se pueda mantener

Como último detalle debemos tener en cuenta que la segunda revisión debiera tener menos código que la primera escritura, pero no debemos confundirnos entre eliminar código innecesario y hacer el código ilegible o ofuscado. No se trata de eliminar líneas o condesar instrucciones en una sola línea, o cualquier tipo de reducción innecesaria que solo llevara a que el código no sea claro, y que no sea mantenible.

miércoles, 21 de diciembre de 2016

Depurar aplicaciones Android en Windows con AMD

En este artículo, voy a apartar un poco la temática general del blog, que es la arquitectura de software, para hablar sobre un problema reciente que he tenido y la solución que encontré.

Hace unas semanas decidí comprar una nueva laptop aprovechando una temporada de ofertas, hacía mucho que no renovada mí equipo y estaba realmente impaciente. Uno de mis principales objetivos era iniciarme en la programación en Android (con Android Studio). Había tenido algunos acercamientos previos, no profesionales, pero esta vez desea poner en serio manos en el asunto.

Vi una laptop de la que me enamore, tenía una memoria impresionante, un procesador más que decente y una tarjeta gracia aceptable, aparte de un teclado y monitores bastante cómodos. Solo había un problema, tenía un micro AMD.

Había oído que los procesadores AMD era muy lentos a la hora de ejecutar aplicaciones en el emulador de Android, pero me dije “¡Ba!, ¿Qué tal lento puede ser, con esta máquina?”. Así que me la lleve a casa. Todo iba como la seda, rapidísimo, hasta que probé el dichoso emulador. Era lento, muy lento… Ridículamente lento. El emulador tardaba horas en arrancar, ¡Horas! Y cuando arranco, no se podía hacer nada, cada movimiento era extremadamente tedioso.





En este punto podía hacer varias cosas [1]:

  • Devolver la laptop, pero ¡Me gustaba mucho!
  • Comprar una solución de pago, como Genymotion, pero no desea gasta más dinero y menos tener que realizar un poco anual.
  • Compra un o varios dispositivo móvil, y debugear en ellos, pero ¡Ey, me acabo de comprar una laptop, no estoy para derrochar!
  • Buscar algún otro emulador (gratuito), que funcione correctamente.

La solución que encontré fue combinar android-x86, un sistema operativo para pc, basado en Android, y Virtual Box (un sistema para gestionar maquinas virtuales). Con ambos sistemas conseguí tener un emulador rápido que se acoplaba perfectamente a Android Studio.

Estos son los pasos para montar un emulador con Android-x86 y Virtual Box.


Habilitar las capacidades de virtualización de tu equipo


Tanto AMD, como Intel, tiene capacidades de virtualización para acelerar el uso de máquinas virtuales, pero por defecto vienen, casi siempre, apagadas. Aunque no es necesario, si es muy recomendable que las habilites para el emulador vaya más rápido.


Conseguir el software


Puedes bajar el android-x86 del siguiente enlace, yo tengo android-x86_64-6.0-r1.iso (Marshmallow), aunque puedes usar la imagen que más te convenga:


Android Studio puedes descargarlo de:


Y por último Virtual Box


Procede a Instalar la maquina Android Studio y Virtual Box


Crea un maquina virtual para Android-x86


Inicia Virtual Box y crea una nueva máquina virtual que contenga Android-x86. Para lo cual haz clic, en “Nuevo”, y proporciona la siguiente información:

  • Nombre: “Emulador Android”
  • Tipo: Linux
  • Versión: Other Linux (64 bits)
  • Memoria: Yo seleccione 1204 Megas, pero ajústalo a tus necesidades y capacidades.
  • Disco duro: Deje el recomendado de 8 gigas.

Y continúa el proceso hasta finalizar.

Inicia la máquina, cuando te pregunte el disco de arranque indícale el archivo ISO que descargaste (en mi caso android-x86_64-6.0-r1.iso)

Nos mostrara el menú inicial, seleccionaremos

Installation – Install Android-x86 to harddisk

A continuación iremos seleccionando las siguientes opciones:

Create/Modify partitions

Do you want to use GPT, indicaremos que no.

Nos aparecerá el menú de particiones del disco virtual, seleccionaremos las siguientes opciones:

New -> Primary

Seleccionaremos Bootable.

Después Write y por ultimo quit.

Seleccionaremos la partición creada, normalmente sda1, y la formateamos como ext4 (confirmarnos el formateo).

Indicaremos que queremos instalar GRUB (yes), que no queremos instalar EFI (skip).

Indicaremos que quedemos nuestra directorio /system de lectura y escritura.

Se procederá a copiar los archivos.


Iniciar la maquina


Una vez realizada la instalación, debemos arrancar el sistema y configurarlo como si fuera un dispositivo Android cualquiera (con cuenta de Gmail y demás).

La primera ejecución puede llegar a ser un poco lenta (varios minutos), pero las siguientes serán aproximadamente, como iniciar un teléfono móvil (si no es que mas rápido).

Por cierto, el sistema de integración del ratón, no es automático, tenemos que seleccionar la opción “integración del ratón”, dentro del menú “Entrada”, cada vez que iniciemos la maquina y usar la tecla <HOST > (por defecto control derecho) para liberar el puntero de la máquina virtual.


Configurar las dimensiones de un teléfono móvil


Al momento de iniciar nuestro nuevo sistema operativo Android, veremos que tiene el aspecto de un monitor, más ancho que alto. El sistema tiene varias resoluciones y todas cumplen ese patrón.

Para poder usar resoluciones propias de un teléfono, es decir más alto que ancho, tenemos que modificar el arranque de nuestro sistema, además de indicar a nuestra máquina virtual que soporte dichas resoluciones.

Las resoluciones que recomiendo para emular un dispositivo móvil, son las siguientes:

  • 320x480
  • 480x800
  • 768x1280
  • 1080x1920

Para hacer posible que la máquina virtual reconozca estas resoluciones, hay que ejecutar en una ventana de cmd, los siguientes comandos (con la maquina virtual apagada):

VBoxManage setextradata "Emulador Android" "CustomVideoMode1" "320x480x16"
VBoxManage setextradata "Emulador Android" "CustomVideoMode2" "480x800x16"
VBoxManage setextradata "Emulador Android" "CustomVideoMode3" "768x1280x16"
VBoxManage setextradata "Emulador Android" "CustomVideoMode4" "1080x1920x16"

Ya que estén habilitadas estas resoluciones, iniciamos nuestra máquina, pulsando en la ventana de inicio de GRUB, la tecla ‘e’, para editar la línea de arranque. En la segunda pantalla, la volvemos a pulsar para entrar en el editor.

Debemos dirigirnos al final de la línea de arranque y agregar la configuración vga=ask. Guardamos y iniciamos la maquina, con la tecla ‘b’, para pulsar enter cuando nos lo solicite.

Aquí vemos la las opciones de resolución posible (para ver más escribimos ‘scan’):


Es necesario apuntar, los números de “Mode” que corresponde a cada resolución nueva, en mi caso son los cuatro últimos y son los siguientes:

Modo
Dimensiones
360
320x480
361
480x800
362
768x1280
363
1080x1920

Estos números están en Hexadecimal, a partir de ahora necesitaremos los mismo números pero en decimal, para convertirlos, puedes usar, por ejemplo, esta página http://www.binaryhexconverter.com/hex-to-decimal-converter

Los valores de mis pantallas en decimal quedarían así:

Dimensiones
Hexadecimal
decimal
320x480
360
864
480x800
361
865
768x1280
362
866
1080x1920
363
867

Apunta bien esos valores por que los vas a necesitar en la sección siguiente


Configurar GRUB, para arrancar en diversas resoluciones


Una vez que tenemos los mencionados números de las resoluciones, debemos configurar GRUB, para arrancar una u otra. Para ello, debemos crear nuevas entraras en su archivo de configuración.

Para poder modificarlo debemos seleccionar, en el arranque de la máquina virtual “Android-x86 6.0-r1 (Debug mode)” (o el modo debug que aparezca) en el menú de inicio. Se nos habilitara un Shell donde podremos escribir comandos (posiblemente tengamos que pulsar enter antes de comenzar a escribir):

Los pasos a completar son:

Localizar el archivo menu.lst, en mi caso está en /mnt/grub/.

cd /mnt/grub

Lo editamos con vi:

vi menu.lst

Tendrá una apariencia como esta:




Nuestro objetivo es que acabe con las siguientes entradas:

default=0
timeout=6
splashimage=/grub/android-x86.xpm.gz
root (hd0,0)

title Android-x86 6.0-r1
kernel /android-6.0-r1/kernel quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-6.0-r1
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 320x480x32
kernel /android-6.0-r1/kernel quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-6.0-r1 vga=864
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 480x800x32
kernel /android-6.0-r1/kernel quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-6.0-r1 vga=865
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 768x1280x32
kernel /android-6.0-r1/kernel quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-6.0-r1 vga=866
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 1080x1920x32
kernel /android-6.0-r1/kernel quiet root=/dev/ram0 androidboot.hardware=android_x86_64 SRC=/android-6.0-r1 vga=867
initrd /android-6.0-r1/initrd.img


title Android-x86 6.0-r1 (Debug mode)
kernel /android-6.0-r1/kernel root=/dev/ram0 androidboot.hardware=android_x86_64 DEBUG=2 SRC=/android-6.0-r1
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 (Debug nomodeset)
kernel /android-6.0-r1/kernel nomodeset root=/dev/ram0 androidboot.hardware=android_x86_64 DEBUG=2 SRC=/android-6.0-r1
initrd /android-6.0-r1/initrd.img

title Android-x86 6.0-r1 (Debug video=LVDS-1:d)
kernel /android-6.0-r1/kernel video=LVDS-1:d root=/dev/ram0 androidboot.hardware=android_x86_64 DEBUG=2 SRC=/android-6.0-r1
initrd /android-6.0-r1/initrd.img

Tenemos que agregar nuevas configuraciones basadas en la primera y agregar el atributo vga=<valor de nuestra pantalla> por ejemplo vga=865, siendo el numero indicado, el valor en decimal, que se obtuvo en las pantalla de seleccionar resolución (estando en dicha pantalla en hexadecimal).

Para editar un archivo en vi, tenemos los siguientes comandos

Tecla
Efecto
Ejemplo
Esc
Permite introducir comandos
I
Comienza una inserción
dd
Borra una línea completa
Nyy
Copia N líneas al portapapeles
10yy
p
Pega las líneas del portapapeles
:wq
Salva el archivo y sale

A partir de ahora cuando iniciemos nuestra máquina virtual podremos seleccionar la resolución deseada



Ajustar la resolución


Cuando iniciemos la aplicación, nos daremos cuenta que la resolución de Android, es mayor que nuestro monitor, con lo que aparecerán unas scrollbar con la que nos podemos desplazar, lo cual es bastante incómodo.

Para solucionarlo, podemos pulsar la tecla <HOST>+C, hará que sea redimensionable la ventana de Android, con el nuevo problema que se verá con un “aspecto” raro:




Para solucionarlo dimensiona la ventana de la pantalla, fijándote que la figura central quede circular, con eso obtendrás la resolución deseada. Tómalo como referencia, siempre que cambies el tamaño de la pantalla.



Por otro lado el posible que pierdas frecuentemente el uso del ratón, para recuperarlo pulsa <HOST>+c y activa la integración del ratón, para luego volver a pulsar <HOST> + C y volver a la resolución deseada.


Configura la red


La configuración que yo tengo en la red de la máquina virtual de Android es “Adaptador puente”, si tienes por necesidad otra, ve a esta página ver configuraciones adicionales http://www.android-x86.org/documents/debug-howto




¡Vamos a debugear!


Ya casi hemos llegado…

Este es el único paso que vas a tener que hacer cada vez que quieras debugear tu aplicaciones (y hayas reiniciado tu maquina).

Necesitas “conectar” tu maquina física con la máquina virtual Android, para lo cual necesitas conocer la IP de dicha máquina.

En una terminal de Android, teclea ifconfig, y apunta la IP, que te va a dar (suele ser siempre la misma si así configuras tu router, por si más adelante quieres hacer un Shell).


Una vez que tengas dicha IP, en tu máquina de Windows, teclea el comando

adb connect <IP de la máquina de Android>



¡Listo!, ahora podemos iniciar nuestro Android Studio, y comenzar a depurar.





[1] Otra opción no expuesta es usar el emulador en Linux, donde se comparta de forma nativa, con un muy buen rendimiento, prueba que es lo mejor para ti y elije lo que más te convenga.

lunes, 28 de noviembre de 2016

Arquitectura de un sistema empresarial prototipo


En las entradas anteriores establecimos que la gran mayoría del software empresarial se parece entre sí, y entre otros ámbitos de negocio semejantes. Lo que es diferente es la variabilidad de las características que se implementan, cuales son y de qué forma son implementadas.

Vamos a hacer un pequeño acercamiento a la arquitectura de un sistema empresarial prototipo básico. Se muestra un diagrama de bloques de dicho prototipo:




Nota: Debido a que este artículo se creó originalmente como parte del desarrollo de generador “CapicuaGen”, existe varias partes que hacen referencia a dicho generador llamadas “Posibles uso del generador en este contexto”, las cuales se encuentran en cursiva. Si no se está creando un generador de código, o si no es de interés, la parte relativa a “CapicuaGen”, se puede omitir.

Interfaz de usuario


En esta capa se define la apariencia y la interacción con nuestros usuarios y clientes, debe ser lo suficientemente sencilla para que la usen con facilidad, y lo suficientemente completa para que se sea útil. Posibles interfaces son:


Interfaces tradicionales para monitor (computadora)


  • Interfaz de escritorio: Puede ser para un sistema de escritorio para Windows, Linux, Mac u otros.
  • Interfaz web: Un sitio web tradicional. Aunque HTML y CSS nos garantiza homogeneidad entre los distintos navegadores, ocasionalmente hay pequeñas diferencias de visualizado, que tenemos que tener en cuenta al momento de desarrollar.

Interfaces móviles


  • Aplicaciones: Son las aplicaciones nativas desarrolladas para cada dispositivo móvil. En este escenario tenemos que consideran distintas resoluciones de pantalla y tipos de dispositivo como tablet, o smart phones. Podemos desarrollar aplicaciones para Android, iOS y Windows entre otros.
  • Interfaz móvil web: Es una interfaz Web diseñada explícitamente para dispositivos móviles (considerando el tamaño de su pantalla).

Posibles uso del generador en este contexto



La interfaz representa lo que puede "hacer" y puede "ver" nuestro usuario, y esto debería ser común para todas las plataformas, el generador debiera ser capaz de crear dicha funcionalidad, y una vez que cambie el negocio, rehacer el código automáticamente para que se adapten todas las interfaces a dichos cambios. Sería necesario contar con una característica generadora para cada plataforma deseada.


Interfaz de servicios


Representa la puerta de acceso a la funcionalidad del negocio. Es una fachada que expone la funcionalidad de forma que la pueda consumir apropiadamente la interfaz gráfica. De esta manera aislamos el negocio, de la forma en la que este es expuesto.

Por ejemplo puede exponerse el negocio de las siguientes formas (entre otras):

  • Componentes
  • Web Services
  • Socket
  • RPC
  • HTTP


Posibles uso del generador en este contexto



Debido que es un mismo negocio el que se debe exponer y que solo cambia la forma de exponerse, el generador puede crear automáticamente cada fachada necesaria en base a dicho negocio.


Negocio


En esta capa está el problema que queremos resolver en nuestro sistema, representa, en forma de software, la solución a una necesidad a cumplir por la empresa con respecto al mercado.

En esta capa puede haber diversos elementos y diferentes enfoques de resolución, podríamos distinguir los siguientes elementos:

  • Entidades de negocio: Son elementos que representan al modelo del negocio, la representación debe ser tanto de información (datos), como de comportamiento, aislar los datos del comportamiento, nos llevaría a un modelo de dominio anémico. [1]
  • Flujos de operación: Son elementos que representan que entidades de negocio están vigentes y la forma en la que se convierten en otras. Pueden representar flujos de trabajo que no tengan una correspondencia en una entidad de negocio.
  • Acceso a otros componentes: Representan el punto de entrada a componentes ajenos a nuestro software, pueden ser componentes empresariales o componentes externos a nuestra empresa, en cualquier caso esta funcionalidad está aislada, de forma que otros componentes de negocio u otra capa, ignoran el acceso a componentes externos.


Posibles uso del generador en este contexto



Esta parte es muy dependiente de como diseñemos el modelo del dominio de nuestra aplicación, en base a esto podemos crear elementos como:

  • Entidades de negocio en base a otros elementos como un UML, o una base de datos.
  • Agregar funcionalidad en base a diversas configuraciones.
  • Agregar funcionalidad y comportamiento común de la empresa.

Persistencia


Esta capa se encarga gestionar el acceso a diversas fuentes de persistencia, desde donde obtener y guardar la información de nuestro sistema.


Interfaz de persistencia


Expone las funcionalidades de persistencia abstrayendo al negocio de conocer los detalles sobre la tecnología encargada de esta.

Posibles uso del generador en este contexto


Es posible crear las interfaces de los servicios de persistencia, siguiendo algún patrón de software o algo política empresarial sobre cómo deben persistirse los elementos de negocio.


Proveedores de Información


Son los mecanismos concretos por los que se persiste la información. Gracias a la interfaz de persistencia dichos mecanismo podrían ser cambiados por otros, sin afectar al negocio. Algunos de estos mecanismos son:

  • ORM.
  • Stored Procedures.
  • Sentencias SQL.
  • XML.
  • Archivos de texto.
  • Servicios RESTFul.

Posibles uso del generador en este contexto



La persistencia es una de las grandes oportunidades para los generadores de código [2]. Dependiendo de nuestro diseño puede convertir los modelos, en tablas y crear los puntos de acceso para dichas tablas, ya sea por SQL, Stored, o tecnologías ORM. Por otro lado si nuestro diseño comienza por la creación las tablas y procedimientos almacenados (cosa que en principio no es recomendable), se puede crear el acceso a la base de datos, y el modelo a través de ella.


Abstracción del acceso a datos


Mientras la capa anterior trabaja sobre la tecnología de persistencia, esta capa proporciona acceso a dicha tecnología, sin preocuparse donde esté ubicada “físicamente” dicha tecnología. Por ejemplo si el destino es un documento XML, dicho documento puede guardarse en un archivo, en una base de datos, o en cualquier otro tipo de repositorio. Si el destino fuera una base de datos, esta podría ser SQL Server, Informix, MySQL, SQLite, o cualquier otro. Esta capa sabría cómo comunicarse con cada uno de estos proveedores, con independencia de la capa anterior. Igualmente esta capa se encargaría de cualquier tipo de la configuración sobre conexiones y localización de archivos, acorde a las políticas de la empresa acerca del almacén y la seguridad de esta información.

Posibles uso del generador en este contexto



El generador puede ayudarnos a crear el código necesario para el acceso a los repositorios de información, y además puede generar distintos accesos, para simular diversos esquemas de persistencia en un ambiente de pruebas o de desarrollo.


Seguridad


Es una capa que afecta a todas las demás independientemente de lo profundas o externas que sean [3]. Los servicios que ofrecen la capa de seguridad son (entre otros):

  • Autentificación: Garantiza que la persona que está usando el software es quien realmente está identificada ante el sistema.
  • Autorización: Asegura que la persona autenticada, solo pueda realizar las tareas sobre las que tenga autorización.

Posibles uso del generador en este contexto



El generador puede crear distintos tipos de seguridad y agregarla en los puntos requeridos ya sea por programación orientada a aspectos, o cualquier otro mecanismo.


Políticas empresariales


Implica cualquier aspecto empresarial, que se pueda aplicar de forma vertical en cualquier punto de nuestro sistema. Pueden ser, entre otro:

  • Reglas empresariales que deben cumplir todos los sistemas.
  • Mecanismos de Cache
  • Mecanismos y política de bitácoras y trazabilidad
  • Inyección de código
  • Gestión de dependencias
  • Validación de datos
  • Control de excepciones

Posibles uso del generador en este contexto



Dependiendo de qué tipo sea la política empresarial, el generador de código, puede ayudarnos a introducirlas en los lugares adecuados de nuestro software, y encargase de “replicarlas” en el caso que estas cambien.


Acerca de las arquitecturas empresariales


Si bien lo mostrado anteriormente es un ejemplo de una arquitectura empresarial prototipo, hay que tener en cuenta que debemos usar la arquitectura adecuada para resolver cada problema en concreto. No existe una arquitectura que sea indicada para resolver todas los necesidades de software a los que se enfrenta un empresa.

Para considerar una arquitectura software adecuada, esta debe cumplir lo siguiente:

  • Que resuelva la necesidad de negocio de forma adecuada.
  • Que sea sencilla de entender y de explicar.
  • Que sea mantenible.




[1] El modelo de dominio anémico, es un antipatrón de diseño, en que se usa un modelo del dominio, sin lógica de negocio, lo cual rompe el paradigma de la orientación a objetos donde dichos elementos (información y comportamiento) van juntos en una misma entidad.


[2] Jack Herrington, expresa en su libro “Code Generation in Action”, que el principal motivo por el cual comenzara a usar generación automática de código, son las experiencias y dificultades que tuvo trabajando con capas de acceso a datos, como menciona el capítulo 6: “Teaching engineers how to use code generation for database work is my primary reason for writing this book. This motivation comes from some personal experiences with database work.”


[3] Principio “Defense in Deep”

lunes, 24 de octubre de 2016

Diseño de una fábrica de software


Analicemos los elementos necesarios que necesitamos para crear nuestra línea de producción de software , basado en un esquema de “Fabrica de software”, que se puede implementar dentro de nuestra empresa, ya sea que esta tenga un departamento de desarrollo de sistemas o que el giro de la empresa sea el desarrollo de sistemas en sí.


Estándares de programación: Es una colección de reglas de programación que define como debe crearse el software de nuestra empresa , es importante que todos los programadores los conozcan y respecten. De esta forma cualquier codificador del equipo podría asumir cualquier tarea de programación o mantenimiento con una curva mínima de aprendizaje. Deben de existir herramientas que validen de forma automática que los estándares se cumplan.

Metodologías adecuadas: Debemos trabajar de la forma correcta y que dicha forma sea conocida y cumplida por todos los integrantes del equipo. Debido a las características de nuestra línea de producción, en que muchos elementos serán generados automáticamente, puede utilizarse un enfoque ágil (como XP, o Scrum), en el que se presenten cada poco tiempo un prototipo que a la vez sirva para definir y acércanos más a la necesidad final del cliente (En las metodologías agiles se asume que el software va a cambiar y eso se valora como algo positivo).

Patrones de software : Es necesario que el equipo de desarrollo conozca los patrones de software y los sepa aplicar de forma adecuada, igualmente nuestro generador puede implementar automáticamente los patrones de software, para garantizar que se usen correctamente.

Consumo de framework de terceros: Es necesario identificar los componentes existentes en el mercado que nos pueden ayudar en nuestro desarrollo . Muchos de estos componentes resuelven problemas que a nosotros nos pueden resultar complejos o los más probable que estén fuera del ámbito del problema de negocio que queremos resolver (por ejemplo cuando creamos un portal web , no queremos crear un Framework MVC, por que ese no es nuestro objetivo real, por eso usamos alguno previamente existe como ASP.NET MVC o Apache Struts). Es importante encapsular los framework elegidos apropiadamente para no generar dependencias externas excesivas, para ello, nos será muy útil nuestro generador de código que puede crear las interfaces adecuadas hacia dichos frameworks (y cambiarlas si es necesario).

Desarrollo de framework empresariales propios: Se encapsularan los componentes y funcionalidades comunes que se hayan sido desarrollados dentro la empresa . Cualquier funcionalidad que pueda ser global, se convierte en una herramienta que podrá ser usada en cualquier futuro desarrollo . Nuestro generador puede administrar dichos componentes.

Control de versiones: En toda fábrica es necesario tener controlado el software generado, permitir "viajar" sobre distintas revisiones y sobre distintas ramas de un mismo producto , para ello podemos usar herramientas como SVN o GIT.

Generador de código: Es el encargado de generar la gran parte de nuestro sistema . Todo característica repetible, que se propague en dirección vertical u horizontal en nuestra aplicación, se convertirá en una parte de este generador , una característica a incluir en un catálogo común.

Un característica común repetible, no es un fragmento de código, ni una librería que se usa en varios lugares, sino una parte del desarrollo , que puede ser reusada en otros desarrollos, esto incluye la parte del análisis y del diseño, no solo del código. El código se generara automáticamente adaptándose a la circunstancia indicada para el sistema que se quiera hacer.

Por ejemplo si empresarialmente definimos que nuestros sistemas deben tener cierta arquitectura, existirá una característica (o conjunto de ella), que se encarga de generar el código que respecte dicha característica. El código por sistema será diferente pero se habrá generado automáticamente, en base a un análisis y diseño que se realizaron previamente. El código de la misma forma, podrá cambiar de arquitectura, si cambiamos la característica generadora, o podrá crearse simultáneamente para varias arquitectura, por ejemplo podríamos desear que se genere nuestro software para escritorio y para teléfono móvil (Android o iOS ). De esta manera para una misma lógica de negocio , se crearan diferentes arquitecturas de forma automática.

Hay que considerar que para resolver el desarrollo de un sistema no se puede usar cada uno de los elementos previamente mencionados como única solución (de hacerlo caeremos en el problema del martillo de oro ). Es necesario combinar adecuadamente todos los elementos, para conseguir un software estable y con escalable a futuro:

Los estándares y las metodologías por sí solo, nos dan las reglas y las buenas prácticas sobre cómo crear nuestro software , por otro lado los patrones de software deben usarse de la forma y en los lugares correctos.

El abuso de los frameworks externos nos genera una dependencia, tanto al nivel de arquitectura, como técnicamente. Cuando estamos muy atados a un framework, y este no resuelve un problema en concreto, la solución puede volverse tremendamente complicada y enrevesada, entorpeciendo el mantenimiento del producto .

Intentar resolver todos los problemas con framework propios tampoco es una solución idónea, puesto que caeremos en dos escenarios posibles para abarcar todas las circunstancias propias de nuestro negocio , o crearemos un framework muy abstracto, que no resuelva nada, o creamos un framework muy concreto, amplio y difícil de manejar y mantener.

Si solo usáramos nuestro generador de código de forma exclusiva, este crearía muchos elementos repetidos, y código innecesariamente largo, haciéndolo difícil de comprender su funcionamiento, y por lo tanto condenado a ir perdiendo su utilidad con el tiempo (por posibles mantenimiento y diagnósticos).

Por todo eso debemos combinar en nuestra línea de producción de software todos los elementos según las necesidades particulares de los sistemas a desarrollar, eso hará que sean sistemas con alta calidad , funcionales y escalables.

El manifiesto ágil indica que se debe valorar más la colaboración con el cliente sobre negociación contractual y respuesta ante el cambio sobre seguir un plan.

La expresión "Martillo de oro", hace referencia el refrán "Al que tiene un martillo, todo le parece un clavo". Se quiere evidenciar que es fácil creer que nuestra herramienta o tecnología, por buena que sea, puede resolver cualquier problema, aunque no sea apropiada para la tarea.