Proceso de Datos y Arquitectura en Plex - El Post Mas Largo!

Obsydian, Cool:Plex, Advantage Plex, AllFusion Plex...

Moderadores: Jorge Ubeda, pacopicon

Proceso de Datos y Arquitectura en Plex - El Post Mas Largo!

Notapor javucho » Mié Dic 16, 2009 3:04 pm

Hola a todos!

Soy principiante en Plex, pero no así en desarrollo orientado a objetos. A raíz de esto, me anime a escribir largo y tendido acerca de uno de los temas que más dudas me plantea. Si, es muy largo, pero la intención es exponer las dudas en un orden a fin de que sus experiencias y comentarios me orienten hasta que consiga alinearme a la correcta perspectiva.

Desarrollo un proceso que analiza datos de diferentes entidades para registrar el resultado en un segundo conjunto de entidades. El grupo de entidades a analizar se encuentran en un modelo incluido como librería y tanto el proceso como las entidades que contienen la información resultante se encuentran en el modelo principal.

Implementación del Proceso

La implementación del proceso, como requisito, debe ser independiente de plataforma (PIM) permitiendo ser portado a otro motor de base de datos (Actualmente AS/400). Para realizar esto, realizo todo el procesamiento con funciones de tipo ProcessGroup y FunctionShell. Las primeras para navegar por colecciones y relaciones, y las segundas para operaciones del objeto representado en la entidad (según la asignación de responsabilidad), o bien, utilizándolas como fachada.

Como resultado, obtengo un importante “árbol” de llamados.

Así, llego a la primera pregunta.

1) ¿Descomponer un proceso que navega por diferentes relaciones en un conjunto de ProcessGroup y FunctionShell es la opción que todos utilizan?

Agradecería conocer sus decisiones y sus fundamentos para elegir entre las variantes.

Quizás la utilización de un ProcessGroupSQL se considere dependiente de plataforma, o al menos, puede implicar una revisión futura. Mientras tanto, consideré esta opción como válida ya que delego la tarea de integrar información al motor de base de datos, en vez de recorrer las relaciones mediante procesos. Con esto reduzco una buena cantidad de funciones, pero no todas.

Otra opción quizás podría ser crear procedimientos como “Stored Procedures” en motores que lo permitan. Adiós independencia de plataforma, pero elimino la cadena de llamados.

Hasta este punto, solo obtuve la fuerte recomendación de utilizar solo ProcessGroups y FunctionShells.



Organización del Proceso

Elegido este método de descomposición, continúo con el desarrollo.
Muchas de las funciones dependen de entidades “maestros” que pertenecen a un modelo incluido como librería. Esto me obliga agregar un conjunto de funciones a entidades de la librería y, en algunos casos, exige también la creación de vistas. La dependencia entre estos dos modelos es unidireccional hasta este punto.

Muchas de las funciones agregadas a la entidad, no tienen muchas oportunidades de reutilización y, en algunos casos, estas funciones realizan algún tipo de procesamiento sobre una entidad del modelo principal. Si intento pensar que estas funciones son métodos del “objeto conceptual” que implemento, en Plex, como una Entidad, puedo ver claramente que el servicio lo da el objeto equivocado perdiendo así su cohesión (según Don Larman y si pensé correctamente).

Por ejemplo, un sistema de pronósticos de ventas contenido en un modelo diferente de un sistema de ventas (forzando diferentes modelos para resaltar el ejemplo, pero quizás también por la naturaleza operativa/estratégica entre estos sistemas). El sistema de pronóstico se relaciona unidireccionalmente con ventas, barriendo artículos incluidos en los pedidos y, por cada uno de ellos, afectará finalmente a una entidad propia. Esto daría como resultado un ProcessGroup nuevo en el sistema de ventas, que llamará a una función del sistema de pronósticos.

La realización de esto tiene consecuencias conceptuales a mi entender.
Una podría ser que ahora la dependencia entre modelos es bidireccional, aumentando el acoplamiento entre los dos modelos. Si quisiera quitar el sistema de pronósticos, o reemplazarlo por otro, debería trabajar en aislar las funciones que están distribuidas entre múltiples entidades, o bien, mantenerlo con listas, paquetes, etc.

Se me recomendó no utilizar “uses view” en funciones, a fin de conocer a primera vista el lugar donde proviene. No estoy de acuerdo, pero hice caso a la recomendación.

Todo esto me lleva a estar casi seguro que todavía no adquirí una perspectiva correcta de lo que es Plex. Pero igualmente, me lleva a mi segunda pregunta.

2) ¿Cómo organizo las partes del proceso (funciones) sin sobrecargar a la entidad con funciones que poco tienen que ver con ella? ¿Elegí una forma incorrecta para implementar este proceso?


Control de Errores y Excepciones

Siempre que se realiza un llamado es necesario comprobar el estado de la llamada. En Plex debo consultar tanto por el valor de retorno como por el estado de la llamada.

Si utilizar funciones para descomponer un proceso algo complejo da como resultado múltiples llamados, luego de cada paso delegado a una función debo controlar con un gran “If”.

No convencido de esto, revise los patrones de XML de Remia, y observe que heredan de una función (por ejemplo, Function With CallHandling) para recibir una subrutina en el diagrama de acción. Esto permite hacer lo siguiente:
Código: Seleccionar todo
Call ENTIDAD.Method
Name Function ENTIDAD.Method, *object
Go Sub Call Handling

Encontré ciertas ventajas esta estructura, pero aun así quisiera formular la pregunta numero tres.

3) ¿De qué forma controlan el estado de las llamadas en sus aplicaciones?

En lenguajes orientados a objetos se utilizan excepciones y es un buen recurso, pero en Plex no existe algo como tal.

Si Plex no posee excepciones puedo suponer que está pensado para que la cadena de llamados sea realmente sencilla, pero considerando que quiero que un proceso de datos sea independiente de plataforma, tengo altas probabilidades de perder dicha simplicidad.

Imaginé que un esquema de “excepciones”, o similar, debería ser soportado a nivel diagrama de acción. El código generado mapearía esto independientemente de las capacidades del lenguaje al que sea generado, incluso generando automáticamente el gran bloque de "If". Se que no disponemos de este recurso, y sé también, que pienso como pensaba en otros lenguajes, por eso necesito su ayuda para alinearme.


Entidades Polimórficas

Muchas veces una tabla en la base de datos almacena conceptos que son sutilmente diferentes, como por ejemplo, factura, presupuesto, remito, etc. Entonces es común ver una entidad que generaliza el concepto. Cuando uno debería visualizar, editar, procesar colecciones de ese tipo de elemento, etc., debería encontrar los métodos para cada “rol” que la entidad pueda asumir.

Con esto, asumo que una entidad de estas características corresponde a un estereotipo diferente. Si considero entidades como “entidad simple”, “Suite de Edición”, etc. serian aplicables a las especializaciones de esta entidad, pero afectarían a la tabla original.

Entonces mi pregunta numero 4.

4) ¿De qué forma estructuran una entidad (o entidades) de este tipo? ¿Qué organización dan al esqueleto de la entidad?


Despedida

Si llega a este punto, sus recomendaciones y comentarios tienen toda mi atención. Quizás todos mis comentarios fueron felizmente, o no, lo suficientemente disparatados como para causar risa, con lo cual también me alegro. Para ambos entonces, Muchas gracias por leerme, y les agradezco de antemano cualquier comentario que aporte a mi aprendizaje y el de los lectores.

Saludos a Todos!


Javucho
javucho
 
Mensajes: 2
Registrado: Jue Jun 04, 2009 4:07 pm

Efectivamente es el post mas largo.

Notapor Adolfo » Jue Dic 17, 2009 12:04 pm

Madre mía, vaya Biblia!!!!!!

Intento responderte desde mi punto de vista, que no tiene por que ser el mejor, pero es el mío.

1. Si quieres garantizar independencia de plataformas debes utilizar lo que te aporta el entorno o definirte tus propias funciones. El realizar procedimientos almacenados es generalmente dependiente de máquina así que te lo desaconsejaría. De igual forma los ProcessGroupSQL.

2. Las veces que he trabajado utilizando un modelo desarrollado como librería he actuado de la siguiente forma.

Supón que necesitas acceder a una entidad de la librería para recuperar una serie de datos. La entidad en cuestión no tiene ninguna función que permita recuperar de manera optima la información que necesitas.

Desde mi punto de vista tienes dos opciones.

La primera y mas simple es crear la función que necesitas en la entidad de la librería. Este procedimiento podría considerarse un inconveniente ya que implica realizar modificaciones en una librería .

La segunda es ignorar la entidad existente en la librería y crear una exactamente igual en tu modelo, que tenga una estructura idéntica a la de la librería, con los mismos nombres de implementación, campos, etc. Sobre esta entidad podrías definir las funciones que necesites. Ahora bien, si el problema en el primer caso es el acoplamiento a nivel de funciones en el segundo caso el acoplamiento es a nivel de entidades.

3. No dispongo de la función que indicas, nosotros la gestión de errores la hacemos utilizando dos campos de Environment, Call Status y Returned Status, que entiendo que es lo que realiza la subrutina que mencionas de Call Handling. Call Status indica si la llamada a la función ha sido correcta (supón que la función a la que llamas por cualquier problema no existiera, esto produciría un error en el campo Call Status). Returned Status indica el resultado de la ejecución de una función. Internamente en tu función puedes gestionar un campo denominado Returning Status indicando criterios de error en la operación que esté realizando. El contenido de este campo al finalizar la ejecución de la función se almacenará en el Returned Status de la función llamadora.

4. Supón una entidad genérica que gestione el concepto movimiento. Tu puedes definir una serie de funciones genéricas sobre dicho concepto.

Posteriormente puedes implementarlo para convertir movimiento en pago, abono, factura, etc. Para ello tendrías que hacer una entidad "real" que herede de tu entidad genérica indicando un replace a nivel del campo que te interese (por ejemplo sustituyendo numero de movimiento por numero de recibo) y añadiendo aquellos campos adicionales que necesite tu nueva entidad. Al hacer esto dicho replace afectaría a todas las funciones que hubiera en la entidad genérica.

Tu entidad genérica puede heredar sin ningún problema de entidades tipo EditDetail y similares, al heredar de ella en tus entidades reales la herencia de la entidad genérica se mantendrá.


Realmente me entran dudas sobre si he respondido a tus dudas o si he respondido a lo que te he entendido (tu correo pese a ser largo deja muchas dudas), así que si no te he respondido en algo o te he respondido algo que ya sabías, por favor, no dudes en volver a preguntar.

Un saludo.
Adolfo.
Adolfo
 
Mensajes: 27
Registrado: Lun Dic 05, 2005 5:47 pm
Ubicación: Madrid - España

Notapor javucho » Vie Dic 18, 2009 7:38 pm

Hola Adolfo y amigos del foro,

Muchas gracias por responder. Mi pregunta fue algo general y rescaté cosas interesantes adicionales a lo que preguntaba, pero no exactamente lo que buscaba. Si no me expliqué o dejo muchas dudas, no duden en preguntar.

Tengo comentarios para cada pregunta y las agrego a continuación:

1. Procesos. Estoy de acuerdo completamente con tu opinión, de hecho lo mencioné al enumerar las alternativas que creí posible. Lo interesante es saber si la mayoría implementa procesos complejos desde Plex, evitando al máximo caer en soluciones dependientes de plataforma. Por tu respuesta, ahora entiendo cual es la opción elegida siempre.

La consecuencia es explosión de funciones relacionadas en una larga cadena de llamados y esto se relaciona con los dos puntos siguientes: Organización (del punto 2) y Control de Errores (del punto 3).

2. Tu respuesta a esto me sirve bastante por varias razones. Pero ahora, replanteándome la pregunta, quizás esperaba alguna opinión sobre la forma de organizar las funciones, sin que estas dependan de una entidad.

Bajo el scope de entidades de datos, pensé, conviene poner solo recursos relacionados directamente con la entidad y potencialmente reutilizables. Algo que relaciona a más de una entidad, quedaría fuera de esa “regla”. ¿Entonces donde? Pensé en una nueva entidad con diferente “estereotipo”.

Entonces llego a esto: Uno puede pensar que una entidad es de datos (una tabla, o casi), pero una entidad podría corresponderse con un estereotipo diferente como ser “Facade”, “Proxy” o “Proceso Complejo”, proporcionando un esqueleto acorde sin tablas o vistas. Así, un ProcessGroup que forma parte de un proceso complejo, depende de una entidad que representa al “Todo”. Este ProcessGroup hereda del ProcessGroup de la entidad e incluye la vista mediante el triple “uses view”.

Ante un cambio en una Entidad (de datos), sería natural pensar que los procesos que conceptualmente están relacionados con ella, deberían ser recompilados también. Si necesitara modificar al proceso, tengo una forma de organización natural.

Quisiera saber que piensan sobre esto y si alguien experimentó con algo similar.


3. Control de Errores. Para no aumentar la complejidad del código mediante la consulta de los valores de retorno, otros lenguajes usan “Excepciones” (Si alguien no utilizo nunca, ver http://es.wikipedia.org/wiki/Manejo_de_excepciones). En Plex no tenemos eso, por eso preguntaba si alguien había experimentado alguna variante diferente a la propuesta por Plex (Variables de Entorno para consultar Returned y Call Status). Remia utiliza una variante de la opción que adjunto al final.

4. Lo que quería conseguir sobre este punto, era una forma de organizar entidades que, según el rol que cumplen, exponen diferentes funciones. De la tabla “Factura” quizás puedo almacenar “Remitos” también. Pero no mantengo todas las funciones, pantallas, vistas, etc en la misma entidad con el mismo objeto. Mantener clara las diferencias, tener opción de extirpar las diferencias, etc.
Se me ocurren algunas variantes pero será para otra oportunidad.


Espero vean a donde apunto, cualquier comentario siempre va a ser bien recibido. Desde ya, estoy agradecido a quienes dedican su tiempo a leer y compartir ideas.

Muchas Gracias y Saludos!


Javucho



Control de Errores

Controlar el estado de una llamada en Plex se ve como:
Código: Seleccionar todo
Call [FunctionX]
Name Function: [FunctionX], Environment<*Object>
If  Environment<*Call status> IS <State: OBJECTS/*Call status.*Abnormal> OR Environment<*Returned status> IS <State: OBJECTS/*Returned status.*Abnormal>
    Comment Mostrar aca el Nombre de funcion, errores, etc
    Set  Environment<*Returning status> = <*Returning status.*Error>
    Go Sub  Terminate


La parte condicional y la accion resultante la llevo como subrutina, agregando a una función que herede de FunctionShell llamada “Function with Call Handling”. En el sector de “subrutinas” se agrega la nuestra:

Código: Seleccionar todo
Sub Call Handling
    If  Environment<*Call status> IS <State: OBJECTS/*Call status.*Abnormal> OR Environment<*Returned status> IS <State: OBJECTS/*Returned status.*Abnormal>
    Comment Notificar error (mensaje, llamando a un manejador, etc)
    Set  Environment<*Returning status> = <*Returning status.*Error>
    Go Sub  Terminate


Asi, las funciones que necesitan esa rutina pueden incluirla con el triple “is a Function with Call Handling”, heredando dicha subrutina en la sección. Similar a un Include o un Import de otros lenguajes.

Finalmente, en cada sector del código puedo poner lo siguiente:

Código: Seleccionar todo
Call [FunctionX]
Name Function: [FunctionX], Environment<*Object>
Go Sub Call Handling


Cualquier otra opción es bienvenida.
javucho
 
Mensajes: 2
Registrado: Jue Jun 04, 2009 4:07 pm

Re: Proceso de Datos y Arquitectura en Plex - El Post Mas La

Notapor Jorge Ubeda » Vie Dic 25, 2009 12:31 pm

javucho escribió:Siempre que se realiza un llamado es necesario comprobar el estado de la llamada. En Plex debo consultar tanto por el valor de retorno como por el estado de la llamada.

Si utilizar funciones para descomponer un proceso algo complejo da como resultado múltiples llamados, luego de cada paso delegado a una función debo controlar con un gran “If”.

No convencido de esto, revise los patrones de XML de Remia, y observe que heredan de una función (por ejemplo, Function With CallHandling) para recibir una subrutina en el diagrama de acción. Esto permite hacer lo siguiente:
Código:

Call ENTIDAD.Method
Name Function ENTIDAD.Method, *object
Go Sub Call Handling

Encontré ciertas ventajas esta estructura, pero aun así quisiera formular la pregunta numero tres.

3) ¿De qué forma controlan el estado de las llamadas en sus aplicaciones?

En lenguajes orientados a objetos se utilizan excepciones y es un buen recurso, pero en Plex no existe algo como tal.

Si Plex no posee excepciones puedo suponer que está pensado para que la cadena de llamados sea realmente sencilla, pero considerando que quiero que un proceso de datos sea independiente de plataforma, tengo altas probabilidades de perder dicha simplicidad.

Imaginé que un esquema de “excepciones”, o similar, debería ser soportado a nivel diagrama de acción. El código generado mapearía esto independientemente de las capacidades del lenguaje al que sea generado, incluso generando automáticamente el gran bloque de "If". Se que no disponemos de este recurso, y sé también, que pienso como pensaba en otros lenguajes, por eso necesito su ayuda para alinearme.

Hola Javier!
Largo tiempo después de haber conversado por primera vez, comienzo a acercar algunas ideas...
En primer lugar, acerca del manejo de excepciones:
Este es un asunto que está tratado en cierto modo en Plex mismo, en Objects. Allí existe un marco (una función) dedicada a esto: Exception handler. Deberías heredar de esta, y extenderla. Esta función trabaja con el campo Exception status, que tiene catalogados un número de situaciones que extenderías según tu necesidad. En la ayuda dice esto:
Exception Handler
Library: OBJECTS
This function detects and processes error conditions not generated or handled directly by AllFusion Plex or by any pattern library function.

This function takes the input field OBJECTS/*Returned Status and moves it to the local OBJECTS/Exception Status field. Then it executes any code in the Exception Condition collection point if the value of Exception Status is outside the range normally handled by AllFusion Plex pattern library functions.

This function is not intended to be implemented. To create a version of it, define a function that inherits from this one, using a FNC is a FNC triple. Then add custom code to your function to handle error conditions specific to your application.

Parameter Interface
This function has the input parameter OBJECTS/*Returned Status, for the variable Input.

Yo he usado este mecanismo en funciones servidoras RPG para obtener información de bajo nivel. *Returned Status en realidad devuelve más información que la que cataloga en sus values. Cuando su estado no es successful, allí se puede recoger el código que devuelve el sistema operativo. Pasando este valor a Exception Status, luego se puede tratar en el exception handler.
Adicionalmente, en casos específicos (estoy pensando en el manejo de correo contra Exchange Server), la función que maneja el correo recolecta el resultado de las operaciones, para formatear un mensaje de salida que devuelve un diagnóstico del estado, y el código de error de la operación de correo que haya fallado. Usamos un Format message para dar un formato de salida uniforme que sea capaz de enviar información variada del resultado. Este esquema también lo hemos usado para operaciones de auditoría, devolviendo un mensaje (varying) usando format message para formatear toda clase de mensajes a una salida uniforme.
Última edición por Jorge Ubeda el Vie Dic 25, 2009 1:02 pm, editado 1 vez en total
Jorge Ubeda
Site Admin
 
Mensajes: 229
Registrado: Mié Oct 26, 2005 6:00 pm
Ubicación: Valencia

Entidades Polimórficas

Notapor Jorge Ubeda » Vie Dic 25, 2009 1:01 pm

Entidades Polimórficas
En este caso, no me queda claro si te refieres a polimorfismo en tiempo de diseño, o en ejecución. Dos problemas distintos.
Respecto al primero, comparto la solución de Adolfo: con los patrones es perfectamente posible crear una entidad con la suficiente generalización para que a partir de un patrón puedan expresarse las distintas variantes o especializaciones. Ten en cuenta que no sólo se dispone de las definiciones a nivel de herencia o sustitución (replacements), sino de la potencia de las metaoperaciones, que permiten generalizar una función en múltiples dimensiones (variante, lenguaje, versión, nivel) y posibilidades de funcionalidad. A partir de puntos de inserción (edit points) puedes variar el comportamiento de una función, en el mismo sentido en que en SPL (Software product lines) se propone.
En el segundo caso, polimorfismo en runtime, no lo he practicado nunca, pero creo que deberías basarte en el soporte de Componentes e Interfases. No he tenido mucho éxito en este terreno, ya que de los tres intentos que emprendí, sólo pude completar bien el manejo del API de Plex, pero mal importando componentes de Microsoft. En cierto modo, esta arquitectura se podría implementar no sólo estrictamente a través del modelo de COM, sino también a través del soporte de Java.
Tú dirás de qué versión de polimorfismo hablamos.
Jorge Ubeda
Site Admin
 
Mensajes: 229
Registrado: Mié Oct 26, 2005 6:00 pm
Ubicación: Valencia

Implementación del Proceso

Notapor Dario, Fabini » Vie Ene 08, 2010 4:26 am

Primero, felicitaciones por la forma en que se exponen los temas, veo muy prometedora su participación en el foro.
Utilizar ProcessGroups y FunctionShells ( o mejor ServerShell) es la opción que nosotros más usamos, manteniendo la idea de que la primera solamente recorre la lista seleccionando las instancias deseadas y la segunda realiza el proceso de la instancia.
En general partimos de la base que nuestra entidad mantiene un conjunto de funciones a nivel de objeto, viendo cada registro como una instancia (TIPS de Modelado con Plex desarrollamos una introducción sobre como estructuramos las entidades) y otro conjunto de funciones a nivel del Clase (lista de objetos en cada vista) los cuales son simple recorredores de instancias siguiendo un orden y una selección (no podemos omitir que se tratan de tablas y vistas de un modelo relacional) o funciones que retornan bloques de instancias.
En mucha situaciones la función la función a nivel de instancia es reutilizable en otro contexto. Por ejemplo una entidad Pedido, tendrá las funciones a nivel de instancia (mensajes), solicitarPedido, ejecutarPedido, cancelarPedido, cumplirPedido, etc. Los cuales pueden ser llamados desde un processGroups o simplemente desde un panel que procesa una única instancia.
Este mecanismo puede darse en cascadas, es decir que: procesar una instancia implique recorre una nueva lista que se procesará de la misma forma. Claro que queda un lindo árbol de llamadas a costa de mantener un modelo legible y con componentes reusable. Trabajando en AS400 y SQL Server esto no generó problemas de performance.
Saludos cordiales.
Darío Fabini
Dario, Fabini
 
Mensajes: 22
Registrado: Jue Dic 07, 2006 5:37 pm
Ubicación: Argentina, La Plata

Organización del Proceso

Notapor Dario, Fabini » Vie Ene 08, 2010 4:33 am

Este realmente es un tema interesante, espero no equivocarme en el enfoque: acá la idea que prevalece es mantener nuestros modelos desacoplados, (la idea es introducida tambien en TIPS de modelado con Plex) cada modelo debería presentar su fachada de servicios los más conceptual posible, seguramente algunos servicios obedecerán a contratos externos, pero estos simplemente tienen que brindar los objetos para que el cliente los use y las funciones a nivel de instancias o a nivel de clase (listas) que se consideran públicas, haciendo caso al contrato.

A la hora de diseñar un servicio si creemos que la responsabilidad es de la entidad usaremos el ProcessGroup de lo contrario, si vemos que no es una responsabilidad directa de la Clase analizamos usar un “Interador” para sacar las instacias y procesarlas fuera del scope de la entidad.
Un iterador sería un objeto control externo que consume un BlockFetch, realiza el proceso de las instancia y toma acción en consecuencia llamando a otra función.
Un ejemplo típico se da cuando queremos hacer una proceso que transfiera registros de una entidad Origen a otra Destino, en este caso el proceso “Iterador” puede estar en una tercer Entidad Control que podríamos llamar Transferidor:

Transferidor.Iterador
--While (moreInstance)
-----Origen.Fetch,BlockFetch
---------While (moreInstance)
-----------Destino.Update.InsertRow


La técnica de usar “iterador” permite recorrer instancias de una entidad desde fuera de la entidad usando el BF.

La entidad Transferidor estará en el modelo principal y usará (via contrato) el BF de la entidad Origen que está en el modelo librería.

Si nuestra política es mantener una Fachada en nuestro “modelo librería” entonces nuestro BF tendrá dos indirecciones, a mi juicio vale el costo.
Saludos cordiales.
Darío Fabini
Dario, Fabini
 
Mensajes: 22
Registrado: Jue Dic 07, 2006 5:37 pm
Ubicación: Argentina, La Plata


Volver a Plex

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 6 invitados

cron