viernes, 16 de mayo de 2014

Diseñando Aplicacion usando "diagramas de estados" y "ports" (UML)

Cuando fabricamos una aplicación web podemos usar un Diagrama de Estados (UML) para graficar y analizar el estado en que se encuentra el usuario dentro de nuestro sistema.

La interfaz de usuario de nuestro sistema es una "maquina de estados", cada uno de estos estados puede ser representado por el despliegue de una pantalla o de un conjunto de vistas que conforman una pantalla.

Para comprender el uso de "ports" (UML Ports) debo guiarte primero dentro del diseño con diagramas de estados en una simple aplicación ficticia que le pide a un usuario autenticarse y adquirir un plan que le vendemos para luego proceder a usar el sistema que hemos hecho (supongamos un sistema SAAS cualquiera).

Sistema diseñado en base a estados, maquina de estados, diagrama de estados UML.

El siguiente diagrama ilustra este sistema ficticio en una forma minimalista pero a la vez realista:


Diagrama de Estados de un sistema SAAS sencillo

Notarás que cada "cuadro" lleva un titulo principal (ejemplo: "Autenticarse"), este cuadro es el Estado del Sistema en un momento dado en el tiempo, en otras palabras, el estado "autenticarse" indica que el usuario esta frente a un conjunto de pantallas que le permiten iniciar sesión, autenticarse con google, crear una cuenta etc, pero nada mas allá de autenticarse.

Como toda maquina de estados formal, estas tienen salidas o entradas del estado, el estado autenticarse tiene dos salidas: "tiene plan" y "sin plan", indicando que el usuario que se ha autenticado exitosamente tiene un plan y esta vigente o que simplemente nunca ha seleccionado un plan o este ha expirado yendo en consecuencia a la pantalla (o estado) que corresponda.

Que mas nos dice este diagrama acerca del sistema ? Nos dice que tras autenticarse exitosamente podemos "usar el sistema" si "tiene un plan", el estado "usa el sistema" es un "estado compuesto", muchas pantallas o sub estados pueden conformar este estado mayor, el usuario quizá está listando productos, creando facturas, etc etc, todos estos subestados dentro del estado "usa el sistema" dependen de que el usuario tenga un plan.

UML Ports / Puertos

Ahora bien, qué son esos cuadritos [1] y [2] junto al estado "elige plan" ? Son "puertos del estado", se grafican de esta manera (como un cuadrito adosado al estado).  Que finalidad tienen y que nos dicen respecto al sistema ? La respuesta está en la lógica de negocios y diseño de interfaz del sistema graficado aqui.

Resaltado (verde y morado) de los "UML Ports" del estado "Elige Plan"


Notarás que el estado (o pantalla) "Elige Plan" es alcanzado en dos oportunidades:
  1. (port #1) Inmediatamente tras autenticarse y cuando el usuario no tiene plan.

  2. (port #2) Cuando estamos "usando el sistema" y decidimos "eligir plan" simplemente para hacer un upgrade o cambiar de plan a otro mas favorable. 
El "port" nos ayuda a saber o mantener "la ruta"
por donde provino la llamada
.  

Cuando el estado "elige plan" es alcanzado en el puerto "1", entonces sabemos que estamos en presencia de un usuario recién autenticado que no tiene plan, podemos tomar las medidas respectivas respecto a interfaz de usuario (mostrar mas ayuda, etc), ademas de ayudar a esto el port ayuda a volver al estado anterior, porque podemos ir al estado "autenticarse" o al estado "usa el sistema" dependiendo de la llamada que nos hicieron.

Cómo se lleva a la práctica el diagrama de estados con puertos ?

Se realiza con ayuda de componentes. Siguiendo el ejemplo anterior, supongamos que tenemos un componente que despliega todo el formulario de "elige plan", supongamos que este componente puede ser incrustado en una pagina web y que sin importar cual página sea desplegará un formulario que presenta una lista de planes, un botón "submit" y un botón "Volver", nada mas.

(quienes conocen Wordpress sabrán que podriamos crear un Shortcode que incruste este formulario de elección de plan, si no conoces Wordpress te invito a que leas acerca de este tema, es muy bueno y útil).

Usando este componente que incrusta un formulario de elección de plan en cualquier página podemos ahora crear dos paginas (o vistas): EligePlan1 y EligePlan2, sí, 1 y 2 tienen que ver con los "ports" graficados mas atrás.  Cada una de estas páginas despliega el mismo formulario el cual también. A esta acción se le conoce por el nombre de "componentización" (desconozco si el término esta aceptado por la RAE, pero así se le conoce), la componentización nos ayuda a que fabriquemos un componente dedicado a presentar un formulario, sin importar en qué ámbito será utilizado, aquí ese ámbito es graficado por "el port".

EligePlanForm <componente>

Si salimos del "estado de autenticación" y "no hay plan" entonces presentamos la vista (o página) EligePlan1, la cual incrustará al componente: "EligePlanForm", si estando dentro de esta página recibimos actividad en el botón "Volver" pues volvemos al estado de autenticación.

Si salimos del estado "Usa el sistema" (el usuario quiere cambiar de plan) entonces presentamos la vista (o página) EligePlan2, la cual incrustará al componente "EligePlanForm", si estando dentro de esta página recibimos actividad en el mismo botón "Volver" el sistema no se confundirá y nos enviará a alguna pantalla del estado combinado "Usa el Sistema".

Diagrama de Clases y Componentes con la implementación de "UML Ports"
En el diagrama sobre estas líneas muestro cómo implementar la solución en un escenario de desarrollo basado en Wordpress. Los objetos "eligePlan1" y "eligePlan2" ambos son instancias de una PaginaWordpress, en otras palabras mas simples: crearemos dos paginas independientes en Wordpress. Ambos objetos incluyen un componente llamado: "EligePlanForm" el cual esta hecho en forma de Shortcode. Cómo sabemos todo esto leyendo este diagrama ? debido a los símbolos de UML (no son dibujitos lindos de adorno, son grafos del lenguaje UML).  La notación "port=1" y "port=2" bajo cada objeto indica que en esa instancia marcamos al objeto con un atributo que nos indica en qué escenario esta corriendo el shortcode.  Una implementación real podría ser:


El componente "EligePlanForm" que he mencionado en el diagrama de clases anterior esta siendo incrustado y utilizado en cada una de las páginas indicando información de ámbito (los atributos del shortcode "port" y "volver_a").  De esta manera, al realizar el componente éste sabrá que debe hacer y a dónde regresar tras acción "submit" o "volver".

Todo esto gracias al uso de ports y diagramas de estados UML.











sábado, 25 de enero de 2014

Inyección de Dependencia en Yii Framework para combatir las Hiper-Dependencias Cíclicas.


Inyección de Dependencia, para qué sirve.


La inyección de dependencia es un término muy usado en patrones de diseño, sobre todo común y conocido en Java pero quizá no tanto en PHP o Yii Framework.

La inyección de dependencia implica que un componente implementará ciertos comportamientos para que pueda servir para proveer solución a otro componente.

Esta frase podría ayudar a aclarar la idea:

"Yo (un modulo, componente o extensión) Necesito saber datos de facturación de un usuario, podrían darme un componente que cumpla mis especificaciones para de él poder leer información ? gracias. (Al componente que se supone servirá este requisito se le inyecta una dependencia al módulo para que pueda servirlo)"

El origen de la necesidad de la Inyección de Dependencia: La Hiper-Dependencia.

Muchas veces nos topamos que hemos fabricado un componente o un programa y en algún momento del diseño nos toca agregarle nuevas funciones.  Es aquí cuando comienza el drama: Las Dependencias.


Pensemos que hemos fabricado un componente que no depende de nadie y que es de fácil uso, como el gráfico a continuación el cual dice que una vista simplemente puede llamar al modulo y pedir una lista de usuarios.


El siguiente gráfico UML ilustra la aplicación antes de que el cliente pidiera los cambios que veremos mas adelante:



Hasta este punto, todo va muy bien, la vista recibe los usuarios y los presenta, pero ahora ocurre un cambio en la lógica de negocios:

//TODO: Necesitamos que el [ModuloAutenticacion] ahora nos de información de Facturación de cada usuario o de uno en específico.

Aquí tu podrías pensar:

"..Qué fácil.  Simplemente le agrego al [ModuloAutenticacion] las funciones de facturación, para qué complicarnos la vida, código aquí...código allá...parche aquí...parche allá..."
Gracias a esta "grandiosa" decisión ha sucedido que hemos sacado al módulo de autenticación de su tarea fundamental: Manejar usuarios, no facturación. 

Multiplica esto por la cantidad de lógica de negocio requerida y en pocas semanas tu ModuloAutenticacion se ha convertido en algo que no tiene nombre, pues hará de todo y muy probablemente será HiperDependiente, ha nacido la hiperdependencia en tu sistema.

He aquí la famosa ley de mi papa Pedro que si bien es de la era pasada aplica muy bien aún ya que ataca el punto de atomización de las funciones.

"..Cuando se imprime..se imprime, cuando se calcula..se calcula."

Solucionando la Hiper-Dependencia

En el caso anterior, nuestro [ModuloAutenticacion] podría estar en peligro de ser infectado con "código fuera de concepto" (funciones de facturación), sin embargo la lógica de negocios nos pide nueva información: "datos de facturación", el [ModuloAutenticacion] deberá ser capaz de darla sin caer en hiper-dependencias.

Qué podría suceder mas adelante: que así como hoy la lógica de negocios pide un resumen de facturación también mas adelante la misma lógica de negocios demande otro resumen de otro tipo, no podemos ni debemos darle semejante cantidad de lógica de negocios a un solo componente cada vez que algo nuevo sale al camino.

La clave de la solución a la hiperdependencia:


Como solución: el [ModuloAutenticacion] pedirá que le demos un componente que él usará para obtener de éste último datos necesarios para proveer un resumen de facturación del usuario que está listando o de uno indicado explícitamente.  Esto como alternativa muy eficiente a en contraste insertar código de facturación en el [ModuloAutenticacion].

Para que esto sea posible es necesario que ese componente que le daremos al módulo cumpla con algo para poder ser usado como proveedor de datos de facturación, aquí nace la inyección de dependencia:  cuando pedimos que el componente a ser dado al modulo cumpla con alguna interfaz para poder usarlo. Evitándose así que el módulo reciba cualquier cosa, provocando errores de programación de costosa detección.

El [ModuloAutenticacion] require que quien le provea las funciones de facturación lo haga de una manera tal que él pueda entender, por tanto entran en uso las interfaces (lee este articulo para entender las interfaces), es decir: 
"..Yo (el modulo de autenticación) solicito que el componente que me des para obtener de él funciones de facturación cumpla con este formato (la interfaz)...si no cumple, el programa se colgará."
El siguiente punto describe la configuración.

Configurando al Módulo para recibir un Componente con inyección de dependencia.

El [ModuloAutenticacion] podrá ser configurado para recibir un componente mediante su archivo de configuración de YiiFramework (en el caso de YiiFramework mediante el archivo config/main.php).

Qué diría este archivo de configuración:

"..hágame el favor y dígale al módulo de autenticación que use este componente que le indico acá, el cual cumple la interfaz requerida.."
En programación, algo así:

// protected/config/main.php
'modules'=>array(
   'ModuloAutenticacion'=> array(
      'billing_component' => 'billing',
    ),
),
// ahora declaramos al componente "billing" que cumple la interfaz y puede ser usado
// por el modulo. 
'components'=> array(
  'billing' => array(
   'class'=>'application.modules.modfact.components.MyBilling', 
  ),
 ),
Cuidado con la hiperdependencia.  El módulo de autenticación no va a acceder al componente de billing usando los métodos propios del sistema de Billing en cambio: El modulo de facturación va a leer los métodos de la interfaz, que pare eso se hizo: para que que el modulo dependa de lo que la interfaz tiene y nada mas. Cómo ha quedado el gráfico UML tras la adición de esta configuración:
Te fijarás que hay un nuevo [ModuloFacturacion] que ha sido creado para manejar todo lo relativo a Facturación, con pantallas independientes, formularios, casos de negocio etc, siendo lo mas importante: ofrece un componente (indicado en config/main por: Yii::app()->billing) que tiene una dependencia inyectada: la interfaz IModAutResumenFacturacion. Esta inyección de dependencia asegura que el componente MyBilling (cuya instancia Yii::app()->billing es la que se usa para acceder a él) tiene los métodos necesarios para que el [ModuloAutenticacion] lo pueda consumir. Tras este agregado el ModuloAutenticacion puediese invocar métodos del componente Yii::app()->billing, como los siguientes:
$identity = Yii::app()->user->id;
$saldo = Yii::app()->billing->saldoDisponible($identity);
$estatus = Yii::app()->billing->estadoCuenta($identity);
Pero cuidado !! solo es para que comprendas y veas claro: copiare de nuevo la nota anterior: El módulo de autenticación (o la vista) no van a acceder al componente de billing directamente usando los métodos propios del sistema de Billing en cambio: El modulo de facturación va a leer los métodos de la interfaz, que pare eso se hizo: para que que el modulo dependa de lo que la interfaz tiene y nada mas.   Por tanto vamos a proveerle a la vista un método para que ella reciba datos de facturación sin caer una ruidosa hiperdependencia (causada cuando tu haces que la vista lea al componente Yii::app()->billing "por facilidad"), no accederás a Yii::app()->billing desde la vista, aunque puedas, en cambio lo harás mediante el módulo lo cual asegura las dependencias sanas.
// vista: protected/views/site/vistausuario.php
$identity = Yii::app()->user->id;
list($saldo, $estatus) = 
   Yii::app()->getModule("ModuloAutenticacion")->getAccountStatus($identity);

printf("buenas, mi saldo es: %s, y estoy: %s",$saldo, $estatus);
Cuidado que dije: "Proveerle a la vista un metodo", y no dije: "que la vista use los métodos de la interfaz". Esto ultimo crearía una indeseada dependencia entre la vista y el modulo de facturación. Por tanto, en el modulo de autenticación creamos:
public function getAccountStatus($identity){
    $component = $this->getSelectedBillingComponent();

   $available = $component->saldoDisponible($identity);
   $status= $component->estadoCuenta($identity);
   return array($available, $status);

}
Si te has dado cuenta hay un metodo:
getSelectedBillingComponent()
dentro del método del modulo que hemos creado para la vista. Recuerda además que tempranamente dijimos que el módulo podría ser configurado para recibir cualquier componente que cumpla la interfaz, esto debe ser así para que el modulo pueda ajustarse a casos de negocio, pudiendo usar distintos componentes para distintas ocasiones. Procedemos finalmente a decirle al modulo que lea el componente de billing que tiene configurado para ser usado:
 public function getSelectedBillingComponent() {
  $id = $this->billing_component;  // configurado en config/main
  if(Yii::app()->hasComponent($id)){
   return Yii::app()->getComponent($id); 
  }else{
   throw new Exception("the required component "
    ."has not been yet included in the configuration: ".$id);
  }
 }
Los métodos hasComponent y getComponent son parte de YiiFramework en CWebApplication. Haz click en los links para leer acerca de ellos. Resumen Finalmente nuestra feliz vista puede saber datos de facturación así:
// vista: protected/views/site/vistausuario.php
$identity = Yii::app()->user->id;
list($saldo, $estatus) = 
   Yii::app()->getModule("ModuloAutenticacion")->getAccountStatus($identity);

printf("buenas, mi saldo es: %s, y estoy: %s",$saldo, $estatus);
Sin caer en hiper-dependencias, gracias a la inyección de dependencia, la cual garantizará que las partes de tu sistema será conceptualmente coherentes ofreciendo aquello que se supone deben hacer y nada mas, delegando en otros componentes las especializaciones y aprovechando el framework para ser configurado para cumplir exigencias de negocios de una forma sana y firme.

viernes, 24 de enero de 2014

Agregando lógica de negocios a una aplicación existente.


Post-Análisis, como herramienta para analizar mejor una nueva funcionalidad.

Como punto de arranque y a modo de entrenamiento toma una funcionalidad que hayas implementado a un sistema existente, una específica, la mas clara que tengas, analízala, mira qué hiciste para llevarla a cabo, qué pudiste haber hecho mejor, y muy importante: qué usa el cliente dentro de todo eso que le diste con tanto detalle y lujo: quizá use el 20%. Eso se llama: "post-análisis de casos de uso".

Enfrentas una nueva lógica de negocios a ser aplicada a un sistema existente.

Cuando has hecho este post-análisis entonces serás cada vez mas capaz de hacer un pre-análisis (un análisis) de lo que el cliente quiere, teniendo las reglas de negocio claras, harás una planificación en papel y pizarra (sin estruendosas aplicaciones de planificación, a mano) y solo cuando tengas las reglas de negocio muy claras te darás cuenta que puedes proveer al cliente de una solución entregándola a la aplicación en forma de extensión (y ahí entra Yii), te darás cuenta que todo lo que has analizado es "comprobable" y ahí entra TDD.

Cuando haces un sistema o implementas una lógica de negocios a la aplicación existente y no aplicas éste esquema de análisis al cual me refiero en este post entonces se esta enfrente de un adefesio, un software monolítico, una pieza que no es extensible y que a duras penas podrás ser hecha en colaboración, y menos aun con TDD.

Es orientada a objetos ? de verdad ?

No se trata de crear una "clase" y meterle 500 metodos, luego inyectarle un ruidoso TDD para decir que tu aplicación "es" orientada a objetos. No lo es, es un adefesio, quizá duela pero yo también alguna vez las hice así y se muy bien cómo hacer un adefesio y cómo hacer una aplicación bien organizada.



TDD (Test Driven Development)


TDD no es algo "raro" ni algo a que temer. TDD tampoco es "una cosa que se hace con Eclipse" ni tampoco se aplica de una sola manera.  Como bien dice el nombre es: Test Driven Development, o Desarrollo Guiado por Pruebas, es muy claro el objetivo de TDD.


TDD implica que harás la nueva lógica de negocios pensando en piezas verificables una a una y luego una contra la otra.  El objetivo final es que todo pueda verificarse mediante un programa de pruebas, este programa no es sino un nuevo programa que construyes para que pruebe la extensión que estas fabricando.


TDD es análogo a cuando en una fábrica hacen un motor. Tantas piezas que tiene el motor, quiza todas de primera, pero en conjunto cómo funcionan ? se recalienta el motor ? se quema ? se prende en candela y explota ? Porquee !! si todo funcionaba de maravillas, dirías.  Tu aplicación de pruebas o programa de pruebas es análogo a conectar al motor en un banco de pruebas (siendo tu programa de pruebas la analogía a este banco de pruebas del motor).  Se diseñan pruebas en dos niveles basicamente:


Pruebas unitarias, que verificarán que funciones básicas hacen lo que se espera. Debes construir varios casos para probar cada función, aunque esto no garantice que "el motor no se prenda en fuego", al menos tienen un objetivo claro: "saber que las funciones hacen lo esperado". Es análogo a que en tu banco de pruebas del motor de ejemplo tengas un "tester electrónico" que verifique que la corriente no pasa de 10 amperios, pero solo hasta ahí.

Pruebas funcionales, que prueban todo el conjunto, verifican estados, cómo todo anda en conjunto. Es análogo a que en ese banco de pruebas del motor ficticio al que me refiero antes hagas un cableado que supla un encendedor para el motor, un acelerador y un termómetro. Quizá este cableado que suple estas interfaces para probar el motor no sea el que llevará el motor en su implementación final, pero aseguran que: el motor enciende cuando se le pide, que acelera y que no se calienta.

Cómo detectas un error con TDD ?



Generando excepciones:  throw new Exception("error");  , simplemente la siguiente prueba no se ejecuta hasta que no repares la que genera el error.


Ejemplos:

1. El siguiente archivo de código muestra cómo se hace un banco de pruebas para comprobar el funcionamiento de una parte de la extensión: las funciones básicas, pruebas unitarias y funcionales pero del api básica de la aplicación, en otra palabras de las funciones que se ofrecen como base para otras cosas de mas alto nivel.

https://github.com/christiansalazar/yii-billing/blob/master/YiiBillingTest.php

2. Este programa de pruebas esta hecho para comprobar que las funciones básicas en conjunto trabajan bien, eso si posándose sobre la idea de que las funciones básicas del API hacen lo esperado (enlace anterior).


https://github.com/christiansalazar/yii-billing/blob/master/YiiBillingPaymentsInAdvanceTest.php


Ambos enlaces hacen pruebas funcionales y unitarias por si solos, pero el primer enlace se encarga de que lo básico funcione bien y el segundo de que lo avanzado funcione bien también.
 
Cuando piensas en hacer una aplicación con TDD piensas en comprobación, es decir: cómo probar que lo que voy a hacer realmente funciona.


Evitar las Hiper-dependencias y dependencias recursivas.

Es muy fácil caer en la hiper-dependencia, o dependencia espagueti, una hiper-dependencia es cuando A depende de B quien depende C que a su vez depende de B y de A. Existen mucha teoría de software para evitarlas, son muy daniñas y la mejor manera de evitarlas es cumpliendo la ley de python: "be explicit", es decir, componentes que requiren datos explicitos sin extraerlos "magicamente" de otro componente bajo la mesa. Muchas veces cuando A depende de B y a su vez B depende de A entonces es necesaria un tercer componente: C, el cual recibe a A y B hace el trabajo requerido y evita la dependencia recursiva.


Lee mas acerca de cómo implementar Inyección de Dependencia para evitar las hiper-dependencias.

Ejemplo de una lógica de negocios nueva para una aplicación existente

Esta extensión permite mostrar cómo implementar la facturación a una aplicación existente sin romper o fragmentar la aplicación existente, de un modo extensible, realmente orientada a objetos y con TDD.

https://github.com/christiansalazar/yii-billing 

Ejemplo de cómo se ataca un error con TDD en una capa de negocios.

 https://github.com/christiansalazar/yii-billing/issues/4



sábado, 18 de enero de 2014

Object Modeling Framework (OMF)

 Sitio web de descarga del framework:

http://christiansalazar.github.io/omf/

Qué es OMF ?

OMF son las siglas de Object Modeling Framework, un marco de desarrollo de software que sirve para crear y manipular los objetos, sus propiedades y sus relaciones con independencia del método de persistencia.


OMF esta hecho para proveer a tu aplicación de Objetos, sus propiedades y sus relaciones entre otros objetos, permitiendo además buscar, listar, eliminar. 

La Persistencia en OMF.

OMF almacena todos sus objetos, relaciones y propiedades en un único almacenamiento, el cual puede cambiar, puedes almacenar usando un motor mySQL, Oracle, RAM, o cualquier otro, OMF no depende del método de persistencia.

Para un uso rápido de OMF he creado una clase que viene lista para almacenar los objetos de omf en una base de datos MySQL, pudiendo portarse a otras sin mayor esfuerzo. 

Una característica de OMF es que en cualquier momento puedes cambiar de modelo de persistencia, sin alterar en lo absoluto al sistema entero.


Abstracción

Debido a que todo en OMF se guarda como un objeto o una relación sin importar la especificación para la cual fue creado tal objeto entonces el modelo de datos en OMF pasa a ser inexistente, permitiendo que tu aplicación solo sea diseñada con un modelo de clases pero sin un modelo de datos.


Sin Modelo de Datos, en OMF solo usas un Modelo de Objetos.

En un sistema tradicional un modelo de datos se representa mediante tablas y relaciones entre estas, herramientas como MySQL Workbench son ejemplos de modeladores de datos, en OMF estas herramientas no aplican porque no hay un modelo de datos, solo de objetos.

Normalmente en un sistema tradicional concurren dos modelos: Uno de datos y uno de objetos, mucha gente los confunde y los trata como modelos análogos, lo cual es un error de concepto.  Puedes detectar este tipo de comportamiento en el desarrollador del sistema cuando éste va a crear un nuevo sistema y lo primero que piensa es en: "diseñar las tablitas en mysql".

Un sistema de información esta compuesto básicamente de un modelo de objetos que almacena su información mediante un modelo de persistencia, o modelo de datos.  En OMF solo hay un modelo de objetos, la persistencia es manejada por OMF de una forma abstracta y sin requerir intervención de tu parte.


Los datos almacenados por OMF no se parecen a lo que estas acostumbrado a ver en un esquema tradicional de datos.

En OMF no hay un modelo de datos para ser visto, obviamente puedes ir a ver como OMF almacena la información y hacer una vista, esto está sobre entendido, la diferencia es que no verás la información como tradicionalmente la verías en un modelo de datos relacional tradicional. 

Este esquema no es nuevo, no lo estoy inventando en OMF, es bien conocido en otras áreas de desarrollo, por ejemplo cuando quieres crear una aplicación en Google Apps lo primero con lo que chocarás será con el método de almacenamiento: orientado a objetos, tal cual como es OMF.


Cómo puedo explorar los datos en OMF ¡?


Piensa que OMF almacena objetos, la clase de cada objeto la das tu, las relaciones las das tú según la lógica de tu negocio, si quieres ver que has almacenado entonces deberás crear una vista que explore los objetos que has creado.

OMF está en una fase inicial, muy seguramente mas adelante se creará un explorador de datos que pueda ser usado en cualquier aplicación, por ahora no existe. Bienvenido aquel que ayude a crearlo. 

OMF: Objetos, Relaciones y Propiedades

En OMF todo es un objeto relacionado quizá con otro objeto, y teniendo propiedades con sus valores, también consideradas objetos.

Por ejemplo:

[ jamboree :Mascota ]-----es_mascota_de---->[ christian: Persona ]

en este simple ejemplo tenemos: 

1. dos clases: Mascota y Persona
2. dos instancias: jamboree y christian
3. una relación: "es mascota de"

Mas relaciones entre los objetos, agregando una nueva clase "Marca" y nuevas relaciones: "padre_de" y "consume_alimento"

[ jamboree :Mascota ]-----es_mascota_de---->[ christian: Persona ]

[ jamboree :Mascota ]-----consume_alimento---->[ proplan: Marca ]

[ jamboree :Mascota ]-----padre_de---->[ coco: Mascota ]
[ jamboree :Mascota ]-----padre_de---->[ kim: Mascota ]


En tu sistema de información la clave es definir que objetos tienes y cómo estos se relacionan entre sí. OMF va a guardar (persistir) esta información permitiéndote saber que objetos tienes, cómo se relacionan entre sí y que propiedades tiene cada objeto. 

El diseño de clases se da en tiempo real, no tienes que definir clases en un archivo aparte como lo harías en un sistema tradicional, esto da una ventaja enorme: agilidad de diseño, pero hay que tratarla con cuidado.


Las Propiedades de los Objetos con OMF

En OMF las propiedades de los objetos también son tratadas como objetos y el gran beneficio es que no se requiere alterar el esquema de datos para agregar nuevas propiedades:


[aveo: Vehiculo]-----[color]----->[: Metadata, data=azul]
[aveo: Vehiculo]-----[marca]----->[: Metadata, data=chevrolet]

Este nuevo concepto puede parecer raro pero es muy útil, permite cosas que antes no eran posible de hacer con facilidad: como ejemplo podemos decidir "quien puede leer" la propiedad "color" de un "Vehiculo", quizá las demás propiedades puedan ser accesibles por un usuario dado, pero no el color.

OMF te da un getter y un setter para acceder a propiedades de los objetos.

Un Ejemplo con OMF

Hagamos un ejemplo simple, para que se comprenda la idea:


El caso de negocio:

"..Una empresa vende vehículos y quiere saber cuantos vende en un mes y mediante que vendedor..."

Análisis del modelo:

Tenemos las siguientes clases:  Empresa, Vehiculo, Vendedor

y las siguientes relaciones entre sus instancias:

[:empresa]----vende--->[:vehiculo]---mediante--->[:vendedor]

Según el punto de vista podriamos decir que el Vendedor "ha vendido" tales Vehiculos, por tanto cambiemos un poco las relaciones:

[:empresa]---vende--->[:vehículo]
[:vendedor]---ha_vendido---->[:vehículo]
[:vehículo]---vendido_por--->[:vendedor]


Por qué es importante esto de ver la información desde distintos puntos de vista ? porque depende de cómo el negocio quiere obtener la información, el dueño de la tienda de vehiculos puede preguntarnos:

"Cuantos vehículos ha vendido este agente"
o
"Que agente vendió este vehículo"


Podríamos también decir que es una relación redundante si lo vemos desde el punto de vista de un sistema tradicional porque mediante una relación llegas a la otra, pero en programación orientada a objetos: hablamos de objetos, no de modelos de datos y en esto se enfoca OMF.

Como se implementa una solución con OMF ?

Siguiendo lo expuesto en el párrafo anterior, vamos a programarlo con OMF.


ver el codigo en pastebin.com

    #podemos crear objetos y asignar propiedades a estos de forma dinámica:
    $api = new OmfDb();
    $id = $api->create('Empresa');
    $api->set($id, 'razonsocial', 'Vehiculos ABC');
    $api->set($id, 'rif', '123456');
    $api->set($id, 'direccion', 'en algun lugar del mundo');
     
    #podemos buscar los objetos creados:
    foreach($api->find("Empresa","rif","123456") as $obj){
         list($empresa_id) = $obj;
         printf("razonsocial=%s\n", $api->get($empresa_id, "razonsocial"));
    }
     
    #podemos listar que propiedades se han definidos para una instancia 
    #(no la clase, en OMF cada instancia maneja sus propiedades)
    foreach($api->listPropertys($empresa_id) as $propertyname)
       printf("propiedad: %s, valor: %s\n",
            $propertyname, $api->get($empresa_id, $propertyname));
     
    #podemos listar todas las instancias de clase "Empresa":
    # (find y listObjets se parecen, find busca objetos de clase pero 
    # conteniendo un atributo, en cambio listObjects busca todos los objetos 
    #de una clase, con opciones para paginar)
    foreach($api->listObjects("Empresa") as $obj){
       list($empresa_id) = $obj;
       printf("razonsocial=%s\n", $api->get($empresa_id, "razonsocial"));
    }

 Muy bien, este último ejemplo es para crear la empresa, establecer sus propiedades, listar, buscar,  lo mismo aplica para crear el Vendedor, el Vehiculo, ahora vamos a concentrarnos en mostrar cómo crear las relaciones:

 

    #podemos crear objetos y asignar propiedades a estos de forma dinámica:
    $api = new OmfDb();
    $id = $api->create('Empresa');
    $api->set($id, 'razonsocial', 'Vehiculos ABC');
    $api->set($id, 'rif', '123456');
    $api->set($id, 'direccion', 'en algun lugar del mundo');
     
    #podemos buscar los objetos creados:
    foreach($api->find("Empresa","rif","123456") as $obj){
         list($empresa_id) = $obj;
         printf("razonsocial=%s\n", $api->get($empresa_id, "razonsocial"));
    }
     
    #podemos listar que propiedades se han definidos para una instancia 
    #(no la clase, en OMF cada instancia maneja sus propiedades)
    foreach($api->listPropertys($empresa_id) as $propertyname)
       printf("propiedad: %s, valor: %s\n",
            $propertyname, $api->get($empresa_id, $propertyname));
     
    #podemos listar todas las instancias de clase "Empresa":
    # (find y listObjets se parecen, find busca objetos de clase pero conteniendo 
    # un atributo, en cambio listObjects busca todos los objetos de una clase, 
    #con opciones para paginar)
    foreach($api->listObjects("Empresa") as $obj){
       list($empresa_id) = $obj;
       printf("razonsocial=%s\n", $api->get($empresa_id, "razonsocial"));
    }
     
    #creamos Vehiculos para ser ofrecido en la lista de vehiculos de la Empresa:
    #
    $vid1 = $api->create('Vehiculo');
    $api->set($vid1, 'vin', '991991991');
    $api->set($vid1, 'marca', 'Chevrolet');
    $api->set($vid1, 'color', 'Azul');
     
    $vid2 = $api->create('Vehiculo');
    $api->set($vid2, 'vin', '991991992');
    $api->set($vid2, 'marca', 'Ford');
    $api->set($vid2, 'color', 'Fiesta');
     
    $vid3 = $api->create('Vehiculo');
    $api->set($vid3, 'vin', '991991993');
    $api->set($vid3, 'marca', 'Chevrolet');
    $api->set($vid3, 'color', 'Malibu');
     
    # hasta este momento los vehiculos estan creados, pero no relacionados con 
    # ningun otro objeto, hagamos las relaciones:
    $empresas =$api->find("Empresa","rif","123456");
    list($empresa_id) = $empresas[0];
     
    # relacion: la empresa vende vehiculo
    $api->createRelation($empresa_id, $vid1, "vende");
    $api->createRelation($empresa_id, $vid2, "vende");
     
    #ahora un vendedor vende estos dos unicos vehiculos ofrecidos:
    $ag1 = $api->create('Vendedor');
    $api->set($ag1, 'rif', '881881881');
    $api->set($ag1, 'nombres', 'Christian Salazar');
     
    $ag2 = $api->create('Vendedor');
    $ap2->set($ag2, 'rif', '881881882');
    $ap2->set($ag2, 'nombres', 'Otro Vendedor');
     
    $api->createRelation($ag1, $vin1, "vendedor");
    $api->createRelation($ag1, $vin2, "vendedor");
    $api->createRelation($ag2, $vin3, "vendedor");
     
    #como sabemos que vehiculos vende "Christian Salazar" ?
    foreach($api->getChilds($ag1, "vendedor", "Vehiculo") as $obj){
       list($vehiculo_id) = $obj;
       printf("vende: %s %s %s\n",
         $api->get($vehiculo_id, "vin"),
         $api->get($vehiculo_id, "marca"),
         $api->get($vehiculo_id, "color")
       );
    }
 
Tras ver este ejemplo te darás cuenta que:

1.  Las clases se han definido en tiempo real, sin recurrir a creación de archivos, ni tablas en la base de datos.

2. Las propiedades de los objetos se crearon tambien en tiempo real, sin requerir hacer modificaciones en la estructura de datos.

3. Los objetos son independientes, las relaciones los unen, dejando a los objetos como lo que son, sin interferirlos con datos propios de las relaciones con otros objetos.

4. Todo persiste en un modelo de datos fijo manejado por OMF, si mas adelante no te gusta mySQL puedes pasar a otro modelo y la lógica de negocios permanece intacta.

5. OMF se lleva bien con un análisis UML, enfocando el desarrollo en aquello que has planificado en tu arquitectura de sistemas.

6. Adiós al modelo relacional del pasado.


Para conocer los detalles del API de OMF :

https://github.com/christiansalazar/omf

domingo, 5 de enero de 2014

Algunos pasos para evitar que hackeen tu aplicación web

Por qué hackean tu aplicación web ?

1. casi siempre: confiado o por desconocimiento, pero cuando eres mas cuidadoso pueden ser por las siguientes razones:

2. cuando no le prestas cuidado a los permisos, dejando que algunos tengan +x o +w al usuario publico o a la parte "world" (linux), o en windows dejando que el usuario "system" (bajo el cual por defecto corre el servicio) use sus permisos de superuser debiendo tu crear un usuario nuevo que corra al servicio web y debiendo tu crear objetos DACL apropiados con sus monitores de seguridad SACL apropiados.

3. cuando admites que un usuario suba un archivo o especifique la ruta de uno, violas la primera ley del validador: nunca confies en el userinput. Causas que el usuario aproveche los caracteres especiales: "." y ".." para alterar tu ruta y asi robarte archivos que nunca debio leer.

4. cuando admites herramientas de terceros de dudosa procedencia que pueden venir con backdoors que funcionan con llamadas GET y POST.

5. cuando generas claves MD5 con herramientas de terceros que te han engañado como a un super idiota, o nunca pensaste que ese "generador de md5" pudo haber guardado el key-pair (clavenocifrada-clavemd5) en su DB para posterior uso incluso contra ti mismo o alimentando bases de datos de robots ?

6. cuando no proteges los formularios de logon o password recovery con captchas y conteos de uso desde una misma IP.

7. cuando vas mas alla en el proceso de intercomunicacion de procesos y no tienes cuidado de solicitudes engañosas enviadas por callbacks falsos. Si quieres un buen ejemplo y mas claro de esto lee como FB solicita un callback para el caso de "login con Facebook", el callback es verificado para evitar este caso. Tambien, tienes el caso de ejemplo de Paypal callbacks, tambien ilustran la forma en como protegerse.

8. cuando en el mismo proceso de intercomunicacion de procesos anterios no tienes cuidado de ataques CSRF. (parecido al caso 7, pero mas orientado a suplantar peticiones reales, el caso 7 no son reales, son falsas).