Caso de estudio: “Dependencia Funcional”

30 04 2008

Hoy fui a la facultad a la materia Gestión de Datos e hicimos un ejercicio de la guía de actividades prácticas. Estamos dando el tema “Dependencia funcional y normalización”. El enunciado es este:

Se desea construir una BD para gestionar la información de los electores en un censo electoral con los siguientes supuestos semánticos:

  • Un elector es identificado por su DNI (D). Todos los electores tienen DNI. Un elector tiene un nombre (N), fecha de nacimiento (F) y sexo (S)
  • Un municipio se identifica por la provincia a la que pertenece (P) y su código de municipio (C). No pueden existir dos municipios con igual código en la misma provincia.
  • Dos municipios pueden tener el mismo nombre (B) pero sólo si pertenecen a provincias diferentes
  • Una mesa está identificada por su municipio, número de distrito (T), número de sección (NS) y número de mesa (M). Los números de distrito se pueden repetir para municipios diferentes pero no dentro del mismo municipio. Igual ocurre con los números de sección respecto de los distritos y con los números de mesa respecto de las secciones.
  • Un elector está inscrito en una mesa, incluida en una sección, a su vez incluida en un distrito, que a su vez pertenece a un municipio.
  • Un elector tiene una dirección, es decir, una calle (L) y un número de calle (E).
  • Todos los electores que residen en la misma calle del mismo municipio están inscritos en la misma sección, aunque pueden estar en mesas diferentes según el número de la calle.

Se pide:

  1. Realizar un modelo de tablas que represente la BD a ser utilizada por el sistema tratando de minimizar la cantidad de tablas.
  2. Llevar el modelo anterior a la tercera forma normal (3FN).

Sinceramente yo no tenía ni idea como arrancar, esto lo dimos en la clase de teoría hace dos semanas creo y no me acordaba nada, asique agarré el libro y me puse a leer. Termino de leer la primer forma normal, comienzo a hacerlo, y la profesora explica como resolverlo. Escuho, atiendo, y me pongo a resolverlo de la forma que explicó. Me quedó así:

  • DNI(D) ->Nombre(N), Fecha de nacimiento(F), Sexo(S)
  • Calle(L), Provincia(P), Código(C) -> Número de sección(NS)
  • Provincia(P), Código(C), Calle(L), Número de calle(E), Número de sección(NS), Número de distrito(T) -> Número de mesa(M)
  • Provincia(P), Código(C) -> Nombre(B)
  • DNI(D) ->Número de sección(NS)
  • DNI(D) ->Calle(L), Número de calle(E)

Justo cuando terminamos de hacer esto, la profesora empieza a desarrollarlo en el pizarrón y agrega una dependencia funcional que nosotros no teníamos:

  • DNI(D) -> Nombre(N), Fecha de nacimiento(F), Sexo(S), Calle(L), Provincia(P), Código(C), Número de sección(NS), Número de calle(E), Número de distrito(T), Número de mesa(M), Nombre(B)

Resumiendo, el DNI determina todos los otros campos. Con los chicos que lo estaba haciendo empezamos buscar a ver si se nos había pasado un axioma en dónde podía llegar a estar dicha relación, aunque sin éxito, no la encontramos. Uno de nosotros pregunta:

  • Alumno: “¿Porqué DNI determina Provincia(P) y Código(C)? Por ejemplo”
  • Profesora: “Mmm… No sé como explicártelo, creo que se deduce del enunciado, es como en la vida, vos sabés dónde votas con tu DNI. Osea, podés saber todos los datos de tu mesa”

En ese momento, sinceramente, no podía creer lo que nos estaba diciendo: “No sé como explicártelo” y además, “Creo que se deduce del enunciado”. Supongo que si hay un enunciado de un problema es para que lo respetemos y que no queden cosas que se sobre entienden, porque justamente esto es lo que trae consigo muchos problemas a la hora de interpretar algo.

Igualmente, me quedó picando y capaz que tenga razón, que se deduzca del enunciado porque existen las reglas de Armstrong con las cuales se pueden inferir en otras dependencias funcionales. Asique cuando llegué a mi casa me puse a leer éstas reglas y a ver si llegaba a la respuesta de la profesora. Estas son las reglas:

  • Reflexividad: si B es subconjunto de A, entonces A->B
  • Aumento: si A->B, entonces AC->BC
  • Transitividad: si A->B y B->C, entonces A->C

De estas tres reglas se pueden deducir otras tres más:

  • Descomposición o proyección: si A->BC, entonces A->B y A->C
  • Unión o adición: si A->B y B->C, entonces A->BC
  • Pseudo-Transitividad: A->B y DB->E, entonces AD->E

La que acabo de encontrar (es la primera vez que lo hago realmente) es esta:

  • Por Unión: DNI(D) -> Nombre(N), Fecha de nacimiento(F), Sexo(S), Calle(L), Número de calle(E), Número de sección(NS).

En ningún lado veo que exista la dependecia de Provincia(P) y Código(C) con DNI(D). Por lo tanto no entiendo de dónde está sacando que sabiendo el DNI de un persona se puede saber la Mesa(M) en cuál vota o la Provincia(P) en la cual vive. Por lo tanto el resto del ejercicio por supuesto que lo tenía todo mal hecho ya que yo trabajé sobre la base de datos del enunciado y ella trabajó sobre la de la vida misma





#1 Modulo: commands

29 04 2008

Para capturar la salida de un comando generalmente utilizaba el módulo subprocess de Python de esta forma:

>>> from subprocess import Popen, PIPE
>>> Popen(['date'], stdout=PIPE).stdout.read()
'mar abr 29 17:08:17 ART 2008\n'
>>>

Hoy viendo el código fuente de un programa (pydf) encontré que utilizaba el módulo commands y como no lo conocía me fijé de qué se trataba. Sirve para hacer lo mismo de una manera más sencilla y legible:

>>> import commands
>>> commands.getoutput('date')
'mar abr 29 17:04:22 ART 2008'
>>>

PD: funciona sólamente en Unix





BDD y Números Romanos

29 04 2008

En la primera y última, hasta el momento, charla del LugLi en la UTN de Santa Fé Gastón mostró lo que es BDD (Behaviour Driven Development) aplicándolo en su lenguaje favorito (vaya uno a saber porqué) con RSpec. Lo que mostró y como dió la charla fue fantabuloso, nos engañó a todos de una forma increible, yo compraba.

Y finalmente… compré. Ayer me puse a buscar info sobre BDD en Google pero aplicado a Python, no encontré mucho, al parecer toda esta metodología es demasiado nueva y está muy verde. Finalmente caí en dos links que salen de la sección implementación de la página oficial de BDD. Uno se llama specipy, que no entendí para nada como se usa, ¡no hay doc!. Y el otro es un plugins para nose, y… justamente no sé lo que es que se llama pinocchio.

Seguí leyendo bastante, y preguntando qué me recomendaban hacer en la lista de PyAr y en el canal. No conseguí ninguna respuesta, no sé si nadie sabía, no lo utilizan o qué pasó. Después caí en el módulo doctest de Python, que sirve para probar comentarios como si fueran sentencias dentro del interprete. Está muy piola. Por ejemplo:

def suma(x, y):
  """Esta función devuelve la suma de los
  argumentos x e y
  >>> suma(2,4)
  6
  >>> suma(24,1)
  25
  >>> suma([2],[4])
  [2, 4]
  >>> suma([3], 5)
  Traceback (most recent call last):
  ...
  TypeError: can only concatenate list (not "int") to list
  """

  return x + y

if __name__ == '__main__':
  import doctest
  doctest.testmod()

Esto lo que hace es, cuando se ejecuta este módulo diréctamente se meten en el intérprete todos los comentarios que empiecen con >>> y se compara el resultado con lo que está inmediátamente abajo de esa línea. Si esta coincide, el test es válido.

Ahora para jugar un poco con esto, ya que quería ver cómo se siente tener que escribir cómo debe funcionar la aplicación y luego escribir el código, me puse a jugar con un ejercicio interesante: “Convertir números romandos a enteros, y viceversa”. Abrí un archivo nuevo, lo guardé como .py y empecé a delirar.

Es medio raro escribir algo de texto y ver que no avanzás mucho, pero después cuando escribís la función ya estás seguro de que funciona :D , y no tenés que testearla manualmente, además en una me pasó que metí la pata y pasé de tener 1 Test Fail a tener 14, lo cual hizo que me de cuenta enseguida que había hecho cualquier cosa.

Todavía no me acostrumbro bien a hacer esto, a veces me desespero un poco y empiezo a tirar código a medida que voy haciendo las pruebas, o bien termino la prueba de una función y enseguida la escribo.

El módulo se puede descargar de acá y un ejemplo de su uso sería algo así.

>>> from roman import Roman
>>> Roman(2)
Roman('II')
>>> Roman('XI')
Roman('XI')
>>> Roman(2.5)
Traceback (most recent call last):
    ...
ValueError: float number is not support
>>> Roman('II') + 5
Roman('VII')
>>> Roman('XXI') * 2
Roman('XLII')
>>> Roman('X') + Roman('XV')
Roman('XXV')
>>> Roman('X') - 25
Traceback (most recent call last):
    ...
ValueError: result zero or negative
>>> Roman(25) + Roman(3995)
Traceback (most recent call last):
    ...
ValueError: result too long

Ahora bien, para qué carajo sirve sumar y restar números romanos no sé, si alguien le encuentra alguna utilidad… Bienvenido sea :)





Flisol 2008

26 04 2008

Hoy participé por primera vez en una Flisol. Este año se llevó a cabo en la UNL (Universidad Nacional del Litoral) de Santa Fé. Intenté ayudar con la organización a último momento, ya que no había mucho movimiento en la lista del Lugli, aunque igualmente no pude hacer mucho porque ya era demasiado tarde. Traté de colaborar con zapatillas, switch’s, cd’s y dvd’s. Algo es algo…

Fui con Gustavo y con Pedro, dos de los integrantes en el desarrollo del juego para PyWeek 6, quizás a uno de ellos es más conocido por otra cosa: spa ejem ejem… Llevé mi máquina, sí, el CPU chiquito que tengo :) . Cuando llegué allá ya estaba Gastón, Emiliano, César, Juanjo y otros chicos más. Charlé un poco con cada uno y después, como no llegaba para instalar algún software me puse a hablar con Gastón sobre la charla que estamos preparando.

Empezamos a hablar, y de a poco se empezó a juntar gente a escuchar lo que decíamos sobre Ruby y Python (¿viste lo puse al revés? ;) ), cada uno con una opinión distinta y tirando algún que otro chiste, medio en joda medio en serio sobre cada uno de los lenguajes. Estuvo bastante entretenido.

Después nos pusimos a jugar un rato tirando algunos ejercicios para desarrollar en los dos lenguajes para luego probar tiempos de ejecución y también poder comparar algo de código, teniendo dos programitas que hacían exactamente lo mismo. Lamentablemente, digamos que debido a la cantidad de gente y el disturbio que se pudo haber generado, mi compañero Gastón, tuvo un problemita con la medición del tiempo :D . Asique se nos demoró bastante lo que pensábamos que nos iba a llevar 15 minutos para empezar a probar y ver algunos resultados. A todo esto venía gente nos preguntaba algunas cosas sobre Linux, y cómo hacer tal o cual cosa, lo que también hizo que se demoraran estas pruebas.

Resumiendo, salió todo bastante mal, no pudimos hacer muchas comparaciones con respecto de los tiempos de ejecución, pero sí hablamos mucho de los dos lenguajes en sí mismo. Yo utilicé por primera vez decoradores y me gustó, me pareció agradable como quedó el código y demás, aunque era un uso muy sutil de estos.

Cuando terminó la Flisol, a eso de las 16 hs, con Gastón y Juan Pablo nos fuimos a comer a un bar del shopping, charlamos bastante sobre Ruby, Python, Java, experiencias de todo tipo y tomamos unas cervezas.





…Python Vs. Ruby… ¿Rivales?

24 04 2008

Desde la primer charla del LugLi en la UTN, hace un par de semanas, que conozco Ruby. Esto quiere decir que ví algo de código, me mostraron algunas de sus características y me dejó algo impactado.

Este lenguaje es muy parecido a Python en muchos aspectos. Sin embargo Gastón Ramos me mostró algunas aspéctos que lo hacen que sea tan bueno como es, y me dejó regulando en como hacerlo en Python.

Hay mucha gente que o está del lado de Ruby o de Python, y ni siquiera quieren mirar al costado para compararlos, son cerrados y hasta incluso rivales. Después de un tiempo le propuse hacer algunas comparaciones un poco más profundas y no que quede solo de palabras, asique decidimos escribir un par de post al respecto. Este es el primero de él, la respuesta de Juanjo y ahora tiro algunas diferencias entre ellos.

Python

  1. Tiene strings inmutable
  2. Lo métodos privados comienzan con __ (doble guión bajo)
  3. Los bloques se delimitan con la identación y : (dos puntos)
  4. Tiene __getattr__()
  5. La sobrecarga de operadores se define como un método especial (comienza y termina con __). def __add__(self) para redefinir la suma.
  6. No tiene constantes
  7. InputRaw con r”C:\Mis Documentos”
  8. Insertar una variable en un texto al estilo C: “Mi variable es: %s” % (cadena.upper())
  9. Necesita paréntesis para llamar a un método
  10. True, False, None, elif, import
  11. Acceso dirécto a las variables de una instancia mediante el operador . (punto)
  12. if __name__ == ‘__main__’: verifica si es el archivo principal
  13. Tiene un guía excepcional para todo programador: import this
  14. Docstring utilizados para brindar ayuda con help()
  15. Las funciones son objetos y puedo crear una referencia a ellas

Ruby

  1. Tiene strings mutables
  2. Los métodos privados van después de private
  3. Los bloques se delimitan con end’s statements
  4. Tiene method_missing
  5. La sobrecarga de operadores es def +(), para redefinir la suma por ejemplo
  6. Tiene constantes
  7. InputRaw con ‘C:\Mis Documentos’, (comillas simples)
  8. Insertar una variable dentro de una cadena al estilo Template (de Django, por ejemplo): “Mi variable es #{variable.capitalize}
  9. No necesita paréntesis para los métodos, los atributos comienzan luego del espacio
  10. true, false, nil, elsif, require
  11. Tengo que definir cuales variables son públicas una por una
  12. if __FILE__ == $0 verifica si es el archivo principal
  13. No tiene un guía built-in
  14. Los docstring se utilizan cuando se llama al comando: rdoc
  15. Hasta ahora, no pude guardar la referencia a una función en una variable

Éstas son algunas de las diferencias que encontré a simple vista en Python y Ruby, pero lo que más me interesa mostrar es cómo hacer algo en un lenguaje utilizando alguna particularidad del mismo, que permita que sea super sencillo o que diréctamente en el otro no se pueda realizar de “ninguna forma“.

Vamos a ver que sale de todo esto. ¿Seguiré con Python o me pasaré a Ruby? ¡CHAN!