1 2 3 1) Explicar ordenadamente (explicar primero lo más importante, luego seguir en orden explicando lo siguiente que corresponda en orden de importancia..) 2) Con velocidad razonable (ni demasiado rápido.. ni aburrido) 3) Emplear palabras fáciles y explicaciones sencillas (tratando de emplear lo más posible lenguaje bien natural… y lo menos posible términos muy técnicos o complicados, ya que no es necesario) 4) Describirle a los alumnos qué es lo que les vamos a mostrar, antes de proceder a hacerlo (ya que si no les damos la explicación previa de lo que pretendemos mostrar, y nos ponemos a resolverlo, ellos tienen que ir tratando de deducir qué es lo que queremos hacer, o a dónde queremos llegar..) 5) Y algo que es muy importante es: mostrarle a los alumnos paso a paso qué opciones vamos seleccionando y cómo vamos procediendo… porque si pulsamos teclas de función sin hacerles saber como procedimos, aparecen diálogos que los alumnos no pueden percibir cómo es que aparecieron.. y se pierden… en cambio mostrándoles paso a paso las opciones que elegimos, pueden seguirnos y tomar notas 4 Otro punto fundamental es que el instructor emplee adecuados.. siempre y sin dudar.. los términos Un ejemplo típico es cuando estamos hablando de UNA TRANSACCION, O DE UNA TABLA… O DE UN NIVEL DE UNA TRANSACCION puntualmente. Es bien importante emplear los términos adecuados una y otra vez… hacer énfasis en que son cosas diferentes.. y marcar bien la diferencia… ya que los instructores damos el ejemplo a los alumnos… y es fundamental no confundirlos, sino por el contrario tenemos que brindarles claridad contínuamente. Otro ejemplo clásico, es cuando nos referimos a una regla o a una fórmula… los alumnos se confunden… he escuchado una cantidad inumerable de veces a los alumnos hablar erróneamente de “la fórmula add” y add es una regla (y no me refiero a que sea grave que un alumno principiante se confunda en esto, claro que no, yo apunto a que los instructores tenemos que corregirlos, y dar el ejemplo contínuamente). Redondeando, tenemos que ayudar a los alumnos dándoles el ejemplo siempre cuando hablamos, mencionando los términos adecuados. 5 6 Veamos el tema: DISEÑO DE TRANSACCIONES Todo usuario GX debe saber dada cierta realidad, definir las transacciones adecuadas que modelen dichan realidad. A menudo encontramos problemas en este punto, el cual es el 1er paso para comenzar a trabajar con GX. Encontramos por ejemplo los siguientes problemas … 7 8 Alumnos que definen transacciones de más, con los problemas que eso genera de : • que se creen tablas físicas de más… • se almacenen datos redundantes en las tablas que se crearon de más… • y queden definidas complejidades innecesarias (a todo nivel: a nivel de la base de conocimiento, a nivel de la base de datos y a nivel operativo) 9 - Alumnos que definen componentes de más en las claves primarias porque no tienen del todo claro lo que implica incluir más o menos atributos en la definición de las mismas. - Y en gral hay alumnos que no tienen fijados ciertos conocimientos puntuales, que les serían de gran ayuda para definir transacciones adecuadamente y con mayor seguridad. 10 Para mejorar la enseñanza de este tema tan importante… un ejercicio que a mi personalmente me gusta mucho y con el cual logro buenos resultados de aprendizaje, es el siguiente: Propongo que tengo 2 empresas distintas que me encargan c/u de ellas una aplicación GX… y resulta que ambas empresas trabajan con PROVEEDORES y PRODUCTOS. Entonces expreso que resulta fundamental preguntar en cada una de las 2 empresas si : • cada proveedor provee muchos productos y cada producto puede ser provisto por varios proveedores… o si en cambio • cada proveedor provee muchos productos y a cada producto lo provee un solo proveedor Esto es fundamental averiguarlo para describir adecuadamente la realidad de cada empresa. Entonces resulta que la 1er empresa me responde que su caso corresponde a lo 1ero que planteé, o sea que cada proveedor provee muchos productos y a cada producto lo proveen muchos provedores. Y la 2da empresa me responde que su caso corresponde a mi 2do planteo, es decir que cada proveedor provee muchos productos pero a cada producto lo provee 1 solo provedor. Y una vez planteada la necesidad de describir estas 2 realidades, que ambas trabajan con los mismos actores de la realidad siendo la relación entre ellos diferente, paso a explicar qué alternativas tengo para describir adecuadamente tanto una realidad como la otra. 11 Ahora bien, para representar la realidad de la 1er empresa, es decir, una relación “de muchos a muchos” entre PROVEEDORES y PRODUCTOS, contamos con varias alternativas de diseño. Entonces le presento a los alumnos estas 4 alternativas de diseño de transacciones… y les hago hincapié en que todas ellas GENERAN EXACTAMENTE LAS MISMAS 3 TABLAS FISICAS. Veamos rápidamente la 1er alternativa. Consta de la trn de Productos de 1 nivel (para registrar a los productos) + la trn de Proveedores de 2 niveles, para registrar a los proveedores y la lista de productos que proveen. ¿Cuáles tablas físicas se crean a partir de estas transacciones? muestro la siguiente slide, la explico y vuelvo a esta. Pasemos a la 2da propuesta… es casi igual a la 1era…. la única variante que presenta este diseño con respecto al anterior, es que el 2do nivel se definió en la trn de productos en vez de en la trn de proveedores… es decir, que en vez de ingresar para cada proveedor, la lista de productos que provee, en este caso se ingresa para cada producto, la lista de proveedores que lo proveen. Ahora, la clave primaria de los 2 segundos niveles se compone de los mismos atributos … y si analizamos ¿cuáles tablas físicas se crearán a partir de la 2da propuesta de transacciones? muestro la siguiente slide, la explico y vuelvo a esta. La 3er alternativa propone 3 trns de 1 nivel: Una para definir a los productos, otra para definir a los proveedores y la 3er trn, plana también, para definir qué proveedores proveen qué productos. Claramente las tablas que se generan en este caso, son las mismas 3 que venimos viendo muestro la siguiente slide, la explico y vuelvo a esta. Y por último, incluso les presento la 4ta alternativa… en la cual la trn de Provedores tiene un 2do nivel de Productos y la trn de Productos tiene un 2do nivel de Proveedores… para que sepan que si hacen esa definición, GX detecta que los 2 segundos niveles tienen la misma clave primaria… por lo que creará una única y misma tabla física asociada a ambos 2dos niveles. Solemos llamar a dichos 2dos niveles “paralelos”, en el sentido que son 2 vías de acceso a la misma tabla física… y en definitiva, se crearán las mismas 3 tablas físicas que venimos viendo muestro la siguiente slide 12 • 1 tabla física para almacenar a los proveedores • 1 tabla física para almacenar a los productos • 1 tabla física para almacena a todas las combinaciones que hayan de proveedores y los productos que proveen, es decir las relaciones. Finalmente redondeo acerca de representar una relación “de muchos a muchos” (N-N) entre 2 actores de la realidad: que las distintas alternativas de diseño, permiten variar en lo que se refiere a las pantallas, es decir a la interfaz para el ingreso de los datos… pero las tablas físicas resultantes para representar una relación N-N siempre tendrán que ser 3: - 1 para registrar los datos de 1 actor de la realidad (como por ej: Proveedores) - 1 para registrar los datos del otro actor de la realidad (como por ej: Productos) - y la 3er tabla para almacenar las relaciones entre los 2 actores 13 Ahora pasemos a la realidad de la 2da empresa. En ese caso, hay una relación “1 a muchos” entre PROVEEDORES y PRODUCTOS. Para describir una relación “1 a muchos” entre 2 actores de la realidad, contamos con 2 diseños posibles… los cuales físicamente generan tablas diferentes. 14 Veamos la 1er posibilidad para describir una relación 1-N entre proveedores y productos: Consta de 2 transacciones: una que define a los proveedores y otra a los productos. Como podemos observar en la transacción de productos, está presente el atributo ProviderId como clave foránea. Es importante hacerle ver a los alumnos que definir una clave foránea implica estar definiendo una relación N-1. … porque naturalmente los alumnos saben definir que una factura tiene un cliente por ejemplo.… y que 1 cliente tiene muchas facturas… y por supuesto que es bueno que lo definan naturalmente … el tema es que muchas veces, al sacarlos del ejemplo que tienen claro y plantearles otra realidad con 2 actores y una relación N-1 entre ellos, tienen dudas y llegan a plantear diversa variedad de propuestas. Entonces, es bueno mostrarles - aunque parezca obvio- que incluir a CustomerId en la trn Invoice, define que: una factura así como tiene 1 fecha, tiene 1 cliente… ahora, que ese mismo cliente puede estar referenciado en distintas facturas. Así conceptualizarán la idea y sabrán que siempre que pongan una clave foránea, estarán definiendo una relación N-1 entre los actores. 15 Ahora bien… luego de hacer énfasis en que relacionar 2 trn’s mediante clave foránea , representa una relación de 1 a muchos… les hago observar a los alumnos que no es lo mismo poner la clave foránea de un lado que del otro… Es decir, que la clave foránea ProviderId en “Product” tal como está, significa que cada producto tiene 1 proveedor y que ese proveedor puede estar en distintos registros de productos… Y si en cambio ponen ProductId en “Provider”, significa lo contrario! Es decir, que cada proveedor provee 1 producto ! y que cada producto puede ser provisto por muchos proveedores! Nuevamente: Aunque parezca todo muy básico… mostrar todo esto a los alumnos, ayuda a que fijen conocimientos claros, eliminen dudas y puedan analizar lo que estan definiendo... 16 Bueno, sobre representar relaciones 1-N habíamos dicho que hay 2 alternativas. Recién vimos la 1era… y ahora pasaremos a ver la 2da alternativa. Esta propuesta consta solamente de 1 trn de 2 niveles. El 1er nivel define los datos de los proveedores… y el 2do nivel define a los productos que los proveedores proveen. Si bien la definición de esta transacción provocará la creación de 2 tablas físicas… las tablas físicas que se crearán a partir de este diseño, diferirán de las que se crearon a partir del diseño anterior que vimos como 1er alternativa de diseño de una relación 1-N. En el 1er caso -si observamos- se creaban 2 tablas físicas: una de proveedores y una de productos… y la clave primaria de c/u de ellas era simple: ProviderId* y ProductId* respectivamente. … y en la tabla de productos, ProviderId es clave foránea. En cambio, si definimos este otro diseño que consta de 1 trn de 2 niveles: la tabla física de proveedores se creará idéntica a la que se crea dado el diseño anterior, pero la tabla física de productos que se creará en este caso, tendrá clave primaria compuesta; es decir, se compondrá de: ProviderId*, ProductId* … y esto significa que: Cada producto se identificará por el código de proveedor + el código de producto… o sea que un producto sin proveedor no se podrá definir (a diferencia del otro diseño) Dado un valor de ProductId, no podré ubicar a un producto… siempre necesitaré conocer al proveedor (ProviderId) para ubicar a un producto Los códigos de productos podrán repetirse… ya que el identificador completo de un producto es código de proveedor + el código de producto… 17 Aquí podemos ver un esquema de las tablas que se crearán a partir de la transacción de 2 niveles que veníamos proponiendo. El proveedor 1 podrá tener productos de código 1 y 2… y el proveedor 2 también podrá tener productos de código 1 y 2… y serán diferentes los productos 1 y 2 de cada proveedor… ..… porque dado que para cada par de valores ProviderId,ProductId se define el nombre del producto.. el producto 1 del proveedor 1 a modo de ejemplo puede ser “Coca Zero”… y el producto 1 del proveedor 2 es una cerveza. 18 Hemos visto entonces 2 alternativas de diseño para representar una relación 1-N entre 2 actores de la realidad. ¿Cómo elegimos cuál diseñar? ¡Eso dependerá de la realidad a modelar! Por ejemplo, como sabemos y hemos mencionado, entre los actores de la realidad: clientes y facturas la relación es 1-N puesto que 1 cliente tiene N facturas y 1 factura es de 1 cliente…… y para diseñar esa realidad jamás se nos ocurriría hacer un diseño 1-N de este 2do estilo que vimos… es decir: en el 1er nivel Customers y en el 2do nivel Invoices…. porque una factura debe poder identificarse y poder ubicarse con tan solo su nro de factura. Las facturas tienen existencia propia por si mismas, sus nros son irrepetibles, y con solo tener el nro de una factura, ya debo poder ubicarla. Entonces para la relación 1-N que hay entre los actores de la realidad: clientes y facturas, no hay duda alguna de que elegiríamos la 1er alternativa de diseño propuesta. Es decir, 2 transacciones Customer e Invoice y establecemos la relación mediante la clave foránea CustomerId en Invoice. 19 Si pensamos ahora en cambio en la realidad de que cada cliente tiene N teléfonos… y cada teléfono es de 1 cliente…. la relación es 1-N… ahora, ¿tiene sentido definir a “teléfonos” con existencia propia? No. ¿Se imaginan ingresando teléfonos en un formulario propio para ingreso de teléfonos, digitando un código, el número de teléfono y a qué cliente pertenece? No tiene mayor sentido.. Resulta más razonable definir a los teléfonos dependientes del cliente, porque siempre voy a conocer al cliente, para definirlos y cuando los quiera consultar. De modo que para esta realidad, optaría por la 2da alternativa de diseño que vimos para representar relaciones 1-N. Ahora bien, si bien para los ejemplos de “clientes y facturas” y “clientes y teléfonos” no tuve dudas de CUAL DISEÑO ERA EL MAS ADECUADO DE ELEGIR… … habrán casos de relaciones 1-N para los cuales tendremos que analizar si se ajusta más UN DISEÑO U OTRO en base a la realidad de la empresa. O sea, no es que uno vaya a ser correcto y otro incorrecto, sino que tal vez para una empresa se adecúe mejor UNO y para otra empresa el OTRO. Si volvemos al planteo de modelar proveedores y productos siendo la relación entre dichos actores de la realidad 1-N…. 20 La alternativa 1 resultaría adecuada para una empresa que: Identifica a sus productos con códigos únicos e irrepetibles. Podrían ser por ejemplo: . códigos propios, es decir códigos internos asignados en la empresa (incluso por el sistema) . códigos de barra con definición de unicidad mundial Para ubicar a un producto, necesitan que tan solo con el código de producto sea suficiente La alternativa 2 en cambio, resultaría adecuada para una empresa que: . emplea los mismos códigos de productos tal como vienen de los proveedores para identificarlos (entonces 2 productos podrían tener el mismo código) . siempre identifican a los productos por proveedor. Sería como que los tienen clasificados por proveedor y siempre se refieren a tal producto de tal proveedor. Si bien este 2do caso planteado es menos común que el 1ero, si fuera esta la realidad de la empresa, el diseño adecuado para representar a los proveedores y productos sería la alternativa #2. Ahora pongámosle nombre a las 2 alternativas. Llamamos a la 1er alternativa de diseño: “1-N FUERTE” porque es un diseño “de 1 actor de la realidad RELACIONADO CON EL OTRO”…. y ambos actores de la realidad tienen identificación “fuerte” por si mismos. Y llamamos a la 2da alternativa de diseño “1-N DEBIL” porque el 2do actor de la realidad queda definido bajo la definición del 1er actor de la realidad, es decir, dependiente de él. 21 22 Ahora bien. Veamos un error más, que había mencionado al ppio... que a veces suelen cometer los alumnos... A veces suelen definir claves primarias con atributos de más, lo cual hace incorrecta a su definición. Veamos con un ejemplo lo que sucede: Se le pide al alumno que modele esta realidad para un hospital: Un médico en una fecha, solamente puede tener una consulta Se le asigna un consultorio para atender Y el alumno propone lo siguiente... 23 Para que alumno visualice su error de diseño… recomendamos hacerle un esquema de las tablas que se crean, con datos de ejemplo. Así visualizarán claramente, que están permitiendo que en la misma fecha, el mismo doctor atienda en consultorios diferentes… ya que basta con que uno de los componentes de la clave cambie de valor, para que los demás componentes de la clave puedan repetir el valor en distintos registros. Así que el consultorio no debe formar parte de la clave, para modelar adecuadamente lo que fue solicitado… sino que el consultorio debe estar como dato… como clave foránea… pero no como componente de la clave primaria, porque eso significa que forma parte de la definición de unicidad de las consultas. 24 A raíz de lo que vimos recién, puede surgir explicar también la diferencia... • Entre definir claves primarias compuestas por el conjunto de atributos que determinen la unicidad ó • definir claves ficticias, es decir, en identificador numérico por ejemplo, con autonumerado. Y lo que hay para explicar al respecto, es que si definimos lo primero... Se está aplicando la definición de clave primaria, entonces se estará controlando automáticamente la unicidad de los datos tal como se necesita. La única desventaja que tiene esto, es que los atributos que son parte de la clave no se pueden modificar... Entonces si queremos cambiar la fecha, o el médico, no se puede (habría que borrar el registro y definir otro). Este sería el unico motivo por el cual elegir la 2da alternativa... Ahora hay que hacerle notar a los alumnos, que es posible definir 2 consultas con diferente identificador... ylos mismos datos de médico y fecha.. así que hay que encargarse de controlar la unicidad requerida de otra forma (como por ejemplo, definiendo un índice unique compuesto por fecha y médico). 25 Bueno, pasemos ahora a comentar otro tema: SUBTIPOS 26 Este es un tema que asusta y tiene fama de complejo ;) … sin embargo nada en GeneXus es complejo Básicamente hay que transmitir que los subtipos nos permiten representar en GeneXus, casos que se dan en la realidad… Si un pasaje tiene 2 ciudades (una ciudad origen y otra destino) los subtipos nos lo permiten representarlo… Si una transferencia de dinero es entre 2 bancos (un banco origen y otro banco destino) es mediante el concepto de subtipos que podremos representarlo también.. Estos casos son los más sencillos de comprender, es decir, cuando la propia realidad nos describe que hay más de una referencia a un mismo actor de la realidad cumpliendo distintos roles, en seguida sabemos que se requerirá definir subtipos. Vamos a ver ahora un ejemplo de cuando nos damos cuenta de la necesidad definir subtipos “un poquito más tarde”.. 27 En este ejemplo tenemos definida una transacción de Proveedores, una transacción de Productos y una transacción de Ordenes de Compras. Vemos que cada Producto tiene un Proveedor asociado... y que cada Orden de Compra tiene un Proveedor también, y una lista de Productos solicitados. Observemos qué controles de integridad se realizan automáticamente en la transacción “Ordenes de compras” : Se controla la existencia del proveedor + Se controla la existencia de cada producto que se ingrese... Ahora observemos lo siguiente: ¿se está controlando que cada producto agregado a una orden de compra sea provisto por el proveedor indicado en el cabezal? No, esto no se controla automáticamente porque ProductId+ProviderId juntos como par, no forman una clave foránea con respecto a alguna clave primaria existente en el modelo.. Esto resulta bueno hacerlo ver a los alumnos, ya que les ayuda a seguir comprendiendo cuáles son los controles que se realizan y por qué…. y cuáles no. Este control entonces, lo tenemos que resolver nosotros. Para ello, como cada Producto tiene un proveedor asociado, lo querríamos inferir en el 2do nivel de la transacción “Ordenes de compras”... pero nos encontramos con que ProviderId y ProviderName ya están presentes en esta transacción en el 1er nivel (ya que justamente queremos comparar el proveedor de la compra con el proveedor del producto ). O sea, que surge la necesidad de definir subtipos. Este es un caso en el que tal vez no nos demos cuenta “de entrada” de la necesidad de definir subtipos, o sea no es el caso de que la realidad nos lo plantee claramente, sino que tal vez encontremos la necesidad un poquito después: al querer inferir atributos que ya estan referenciados en la transacción. Ahora bien, luego de haber detectado la necesidad de definir subtipos, es común que los alumnos tengan dudas sobre cuál de los atributos definir como subtipos. 28 Por ejemplo: ¿sería adecuado definir a los subtipos en el 2do nivel de la trn Orden de Compra? No. Y una explicación que me da muy buenos resultados dar a los alumnos para que entiendan el motivo, es la siguiente: Los nuevos atributos definidos en el 2do nivel de la trn Ordenes de compra, no están presentes en ninguna trn más del modelo, entonces no hay ninguna posibilidad de inferirlos, por lo que GeneXus determina almacenarlos en la tabla física asociada a las líneas de la órden de compra.... Pero nosotros no queríamos digitar y almacenar un proveedor en cada línea, sino que queríamos inferir en cada línea al proveedor del producto. Entonces la solución para resolver nuestro requerimiento es... 29 De esta manera, se logra definir adecuamente el requerimiento. En la trn Orden de Compra, es donde surgió la necesidad de tener una doble referencia a proveedores... y es en el 1er nivel donde definimos atributos subtipos de ProviderId y ProviderName respectivamente, ya que en el 2do nivel, el proveedor de cada producto debe inferirse, así ProviderId y ProviderName deben llamarse igual a como están nombrados en la trn Product. Cambiar en Product nombres de atributos no es una alternativa que se considere... porque no solo que en esa trn no surge ninguna necesidad de hacer cambios, sino que podrían verse afectados otros objetos que referencien a los productos y sus proveedores correspondientes. 30 31 Sobre este tema, me da buenos resultados esquematizarle a los alumnos: • Que todas las reglas que definan sin evento de disparo específico… se irán disparando en tiempo de ejecución interactivamente en la medida que el usuario vaya ingresando valores en los campos… y vayan dando true las condiciones de disparo de las reglas. • Y que en cambio las reglas que tengan on… + un momento de disparo específico pasarán a dispararse después de que el usuario haya presionado el botón “Confirm” … en el orden que corresponda en lo que se refiere al esquema conocido de orden de disparo de los eventos. De modo que hago énfasis en diferenciar que las reglas sin on + evento específico, se van ejecutando interactivamente antes de que el usuario presione “Confirm” y a las que les defina on + evento específico, se ejecutarán después de que el usuario haya presionado “Confirm” en el orden que corresponda y antes o después de la acción que corresponda. Esquematizarle a los alumnos o clasificarle en grandes grupos ciertos detalles, les ayuda a fijar ideas fáciles de recordar y que luego las apliquen a la hora de tener que definir .. 32 Veamos algunos pocos errores típicos que tenemos identificados, para tenerlos presentes, detectarlos y aclararlos.. 33 34 35 Les recomiendo revisar que los alumnos esten actualizando la tabla extendida adecuadamente (en rules de trn’s y en For Each). Ya que a veces no lo preguntan, pero por residuos de programación estructurada (sobre todo autodidactas en GeneXus) escriben comandos For Each de más “con el objetivo de posicionarse” en una tabla.. O invocan a un procedimiento, estando en una trn “para acceder y consultar información” que en realidad en GeneXus está disponible por el concepto de tabla extendida y se puede inferir y manejar directamente. 36 Para terminar solo me resta entonces recomendarles que accedan al sitio de capacitación, en el cual podrán buscar lo que necesiten de forma amigable , como por ejemplo videos correspondientes a distintos cursos, para capacitarse. Asimismo el equipo de capacitación seguiremos elaborando videos cada vez más fáciles, más cortos y menos técnicos. 37 38