Alters

Diesño web: máxima compatibilidad - Diseñando el esqueleto a papel

Buenas!

Seguimos con el tema del diseño web...

Ahora que ya sabemos cómo hacer la web algo más estándar, es la hora de empezar con el diseño en sí.

Pero, para poder diseñar bien algo, primero es necesario hacer bocetos, para ver cómo quedaría todo.

Así, se coge un papel en blanco y se empiezan a plasmar ideas, y cuando tenemos una buena la desarrollamos. Recomiendo usar escala para ver mejor los resultados finales.

Cuando tengamos un diseño que nos agrada, podemos (si queremos) pasarlo a PC. Yo lo hago con Corel y mucha paciencia...

Os dejo el último diseño que hice (img):

img1
El tamaño original es 800x600, y lo hice a escala 3:100 (es decir, en el papel era un cuadro de 24x18, y 3 cm equivalen a 100px).

Como veis es un diseño sencillo: se distinguen tres partes principales (lateral - 5 secciones, central - cuadro grande, superior - barra con 2 secciones).

Al tener la escala, fue fácil llevarlo a tamaño real, y fue también fácil llevarlo a web con CSS.

Obviamente, este diseño va un poco en la línea del producto que promociona; es decir, cada tipo de página puede tener un diseño "más acorde" a ello, de manera que no pondría, por ejemplo, colores apagados (grises, negros) en un diseño de una juguetería infantil.

No solo los colores influyen, sino las formas. Formas redondeadas pueden dar un poco de dinamismo en un diseño, pero también son más difíciles de llevar a cabo.

Veamos un poco en profundidad qué cosas se pueden tener en cuenta a la hora de diseñar:
  • Público al que va dirigido
  • Tipo de producto (por ejemplo, las redes sociales tiran hacia el azul)
  • Contraste fondo/contenido
  • Efectos adicionales (sombras, bordes redondeados...)
  • Tamaño óptimo (para webs pequeñas, pienso que 800x600 es un buen tamaño)
  • Accesibilidad
Hasta aquí, tenemos ya todo preparado para llevar nuestra web de la cabeza a internet.

En la próxima entrada (será bastante corta...), veremos cómo analiza, a grosso modo, el estilo nuestro navegador.

Así que,

¡Hasta la próxima!

Diseño web: compatibilidad máxima - W3C

Buenas de nuevo!

Empezamos con el tema de diseño web, temporalmente.

En esta entrada hablaremos de W3C.

W3C significa "World Wide Web Consultorium", es decir, un consultorio de la WWW. Como tal, tiene herramientas específicas para validar nuestro HTML, CSS... e incluso tiene manuales de referncia de los mismos (incluyendo JS).

Pero, ¿Qué es "validar" un HTML?

Veréis, muchas veces codificamos de manera "no estándar" nuestras web. Esto no significa que estén mal, sino que no es un documento estándar, acorde con las directrices de W3C.

Hoy en día no pasa nada, ya que la mayoría de los navegadores incluyen funciones que "estandarizan" nuestro HTML; pero antaño, no seguir un estándar daba webs muy diferentes dependiendo del navegador.

Bien, ahora no penséis que los estándares son muy complicados... voy a dejar una lista de elementos generales a cumplir para el estándar de la W3C:

  • Cerrar los elementos que no tienen etiqueta de cierre:
    • Ejemplo:
      • <br> no es estándar
      • <br /> es estándar
      • <meta ...> no es estándar
      • <meta ... /> no es estándar
    • Si bien no es obligatorio, a mi me gusta dejar un espacio antes del cierre ("/").
  • Entrecomillar los atributos
    • Ejemplo:
      • <div class=clase1> no es estándar
      • <div class="clase1"> es estándar
      • <img src=./img/css/icon.png> no es estándar
      • <img src="./img/css/icon.png> tampoco es estándar (falta cerrar el elemento)
      • <img src="./img/css/icon.png" /> es estándar
  • Cumplir los requisitos básicos de las diferentes etiquetas:
    • <head>
      • Tiene que tener el tag "title" dentro
    • <img>
      • Tiene que tener los atributos "src" y "alt"
    • <a>
      • Tiene que tener el atributo "src"
    • <html>
      • Tiene que tener un "charset" definido
    • <form>
      • Tiene que tener los atributos "name", "action" y "method"
    • <input>
      • Tiene que tener el atributo "type" y "name"
    • <ul>, <ol>
      • Tiene que tener el atributo "type"

Creo que no me dejo ningún elemento en el tintero... como veis, no es demasiado complicado cumplir con el W3C (al menos con webs simples o muy poco complejas).

El "problema", por así decirlo, viene cuando programamos en PHP (por ejemplo). El uso de comillas se puede hacer algo caótico, sobretodo si hacemos JavaScript dinámico en el que llamamos a funciones con parámetros en forma de cadena (que va entrecomillada...)

Mi sugerencia: en PHP usad (siempre que podáis) las comillas simples, y los textos entrecomillados usando la doble comilla.

Vale, todo esto es muy bonito, pero, ¿Qué implica al diseño con la W3C? para responder haré una pequeña reflexión:

Continuamente salen nuevos aparatos tecnológicos que implementan, de alguna u otra manera, la tecnología de Internet.

Éstos nuevos dispositivos implementarán unas u otras reglas, y éstas pueden o no paliar una codificación "no estándar".

A continuación hago un ejemplo drástico, para que se vea la diferencia:

 - Si haces un documento así:

<body><table><td>HOLA

y lo probamos en chrome, éste lo estructura internamente así (inspeccionando el elemento):

<html><head></head><body><table><tbody><tr><td>HOLA</td></tr></tbody></table></body></html>

Ahora se ve el cambio... ha puesto de todo. Y esto se debe a que los navegadores no vuelcan el código fuente directamente, sino que lo tratan previamente.

Puede que un nuevo navegador no incluya todo esto, por el motivo que sea (menor consumo de recursos, por ejemplo), y entonces... ¿qué pasaría con nuestra web? estaría a merced de los algoritmos del navegador, y la veríamos de vete-tú-a-saber-qué manera.

Sin embargo, en una web estándar W3C, la conversión que hace el navegador es nula, por lo que nos "da igual" cómo trate el código fuente, siempre (en teoría) se verá igual la web.

Por este motivo siempre intento que las web cumplan el estándar.

Podéis pasar el test aquí:  http://validator.w3.org/

Si pasáis el test, os saldrá un enlace para "colgar una medalla" en vuestra web. Con ella los visitantes sabrán que cumplís el estándar (y podéis "fardar" con ella, jeje ;-) )

La próxima entrada la llenaremos con contenido de "maquetar esqueletos a papel".

¡Hasta la próxima!

Diseño web: compatibilidad máxima

Buenas de nuevo!

Empieza una nueva "serie de entradas", para dar tiempo a la serie de las M!nas...

Como dije, hablaremos de diseño web. Diseño compatible, sobretodo.

Antes de todo, comentar que para nada soy ningúno de esos "gurús del CSS" que son capaces de montar verdaderas obras de arte combinando CSS2 y CSS3, y cosas por el estilo... yo el CSS lo uso para diseñar cosas simples. Las cosas complejas las dejo para PHP, JS, y demás...

Os dejo un índice acerca de esta nueva serie:

  1. W3C
  2. Maquetar el esqueleto a papel
  3. Interpretar estilios como el navegador
    1. File
    2. Inline
    3. Direct
  4. Clases con CSS
    1. Ancho
    2. Alto
    3. Posición x e y
    4. Relative, absolute...
  5. Maquetar el esqueleto con CSS
  6. Tips & tricks
    1. Porcentajes
    2. Agrupar contenido en clases superiores
    3. Inherit, initial u omitir
    4. Contenido "centrado"
    5. Contenido que se "redimensiona"
      1. Fondo
      2. Contenido
    6. Jugar con la transparencia
    7. Efectos "misc"
      1. Scroll modificado
      2. Cajas con borde
      3. Modificar "select"
      4. Scroll "dependiente"
      5. Editar listas
    8. Div vs Span
    9. Compatibilizar con otros navegadores

En principio serán 6 entradas, aunque lo más posible es que la sexta esté en varias partes (ya que tiene mucho contenido).

Intentaré ilustrarlo todo con ejemplos, para que quede más claro.

Así, en la próxima entrada hablaremos de la W3C, o dicho de otra manera, cómo hacer webs "estándar". Para mí, este punto es fundamental, ya que una web que cumpla a rajatabla la W3C dice mucho.

Saludos, y

Hasta la próxima!

Varios - Misc

Buenas!

Hacía tiempo que no escribí nada en el blog... llevo severos retrasos con todos mis proyectos... así que, para no estar demasiado sin hacer una entrada "con chicha", vamos a ver varios temas rápidos.

AJAX Cross-Domain (ACD)

Muchas veces habréis oído aquello de "usar API's", si bien no las habéis usado alguna vez (google maps, google calendar...)

Para aquellos que no sepan qué es una API, decir que es una capa de abstracción creada por programadores para facilitar el uso de herramientas web.

Un ejemplo: quiero poner en un mapa dónde vivo (en mi web). Hace tiempo, yo lo hubiera hecho así:

 - Entro en google
 - Busco google maps
 - Busco mi calle
 - Hago un print de pantalla
 - Coloco la imagen en mi web

Sin embargo, las API permiten que mi web conecte con google, y le puedo especificar dónde vivo (en latitud y longitud) y él se encarga de todo (es decir, delegamos el funcionamiento a google). Yo solo me tengo que preocupar de poner una capa (div) para recibir el mapa y llamar al método correspondiente.

Pues bien, uno de los principales problemas que entraña el uso de una API es el ACD (AJAX Cross-Domain).

¿Qué es el ACD? es un impedimento (una medida de seguridad, más bien propia de IE) que impide que una web cargue datos de un servidor externo, tal como indica la imágen "img1" (en rojo marcada la comunicación interrumpida).

img1
Esto frustra todo amago de comunicación con servidores externos. Sin embargo, las API se usan. ¿Cómo?
Pues hay varios métodos:


  • Proxie transparente: esta medida se basa en modificar el archivo .htaccess, con una regla de reescritura, de manera que podemos convertir algo como "http://miweb.com/api" en "http://apiweb.com". Con esto conseguimos establecer un puente, mediante el cual nosotros llamaremos a "miweb.com/api", y mediante el archivo htaccess, estaremos realmente accediendo a "apiweb.com".
    • Ventajas: funciona bien, y de manera simple
    • Inconvenientes: cada cliente de la API tiene que configurar su htaccess (algunos hostings no dejan).
  • Página ACD: es una web (http://www.ajax-cross-domain.com/) en la que te puedes descargar un src (código fuente) de un programa cgi. Mediante htaccess hacemos que lo interprete como un js, y éste hace de puente para solventar el problema de ACD.
    • Ventajas: configurable, seguro
    • Inconvenientes: necesita aceso a ACD, y no todos los hostings permiten interpretar cgi como js.
  • Envoltura: es el método más usable de todos, ya que no necesita de nada por parte del cliente (eso sí, la API tiene que estar preparada para usar envoltura). El método de la envoltura consiste en incluir la llamada a la API dentro de un elemento <script> en nuestra web. De esta manera, nuestra web hará una llamada a la API, para incluír el contenido al script. El contenido que "se crea" es, ni más ni menos que el resultado de llamar a la API deseada.
    • Ventajas: siempre podremos usarla
    • Inconvenientes: el programador de la API tiene que prepararla, y (que yo sepa) solo se puede mandar datos vía GET.
Y, ¿porqué os comento el problema del ACD? pues porque estuve varias semanas luchando con este problema con una API que me tocó programar en mi trabajo, y finalmente lo conseguí solucionar usando el método de la envoltura (y la consecuente remodelación de la API...).

En la próxima entrada (a no ser que sea sobre M!nas), trataré de solucionar el tema del diseño web, para hacer lo máximo compatible con IE, Firefox, chrome, opera y safari.

Para poder seguir entregando material en abundancia, lo haré tipo "serie", como he estado haciendo estas entradas.



Varios

Buenas de nuevo!

Sigo trabajando en la entrada de las M!nas, aunque llevo algunos retrasos...

La semana pasada estuvo muy movida también... espero que esta semana vuelva todo a la normaildad...

Y bueno, este fin de semana estuve en el salón del manga. Como era de esperar nadie llevaba el mismo cosplay que yo :-p (Prince of persia: Warrior Within, con la Water Sword).

Allí conseguí ponerme en contacto con un novato (y con esto no quiero decir que sea malo) desarrollador de videojuegos, así que quizás en un tiempo me meto en ese mundillo. También cogí información de un centro que forma en 3D (y lo hace muy bien, al parecer); si bien los precios son elevado (9.900€ un máster de 9 meses, 19.800 una carrera de 2 cursos), incluye mucho material (incluyen hasta un ordenador), así como también prácticas en empresa.

También conseguí contactos con editoriales varias... resulta que tengo un relato corto escrito y registrado, pero no consigo que salga a la luz... a ver si con estos nuevos contactos consigo algo.

En cuanto al merch que compramos (mi novia, mi buen amigo James y yo) fue variado, aunque este año no hemos encontrado ninguna ganga (el año pasado conseguimos una figura de Bobobo por 20€ - en los otros stands las vendían por 80€).

En cuanto a últimas novedades, estoy metido en un concurso de InfoJobs, que consiste en desarrollar una App para la misma compañía, usando su API. El premio al ganador oscila entre los 10.000 y 12.000€ (así que si - ojalá - ganara sería una buena alegría). Pienso que mi idea es buena; y esto es un buen comienzo, ya que hace falta mucha motivación para hacer algo bueno y decente, y sin una buena autoestima es imposible!

Antes de cerrar esta entrada, decir que me guardo las fotos del Salón del Manga (así como las del anterior) para una posible futura entrada no relacionada con  la informática (como esta, jejeje).

Saludos y...

¡Hasta la próxima!

A buscar M!nas: MSAccess - ampliando VB.net

Buenas otra vez!

Me he pasado el finde descansando y vagueando, que ya tocaba! (13/10/12)

Pero hoy es lunes, así que volvemos a la carga con el blog. Además empezamos la parte de programación.

En esta entrada ampliaremos el juego, usando ADO.net.

ADO.net

ADO.net es un objeto que el ".net" provee, con la función de conectar a las bases de datos sin demasiadas dificultades.

Por así decirlo, crea una capa extra entre el motor de la base de datos y la aplicación .net (así como hicimos con Java hace tiempo, pero de manera nativa).

Hay una serie de objetos que segregan de la utilización de ADO, que son:

  • OleDbConnection: provee la conexión
  • OleDbCommand: contiene sentencias SQL, sirve para lanzarlas
  • OleDbDataReader: se usa para obtener los datos de las sentencias.

Una visualización de ejemplo: supongamos que al iniciar el juego de VB.net, éste conecta con la base de datos y ejecuta un SQL. El esquema sería algo así como indica la img1

img1

El evento onLoad tiene su recorrido en naranja: así, se puede ver cómo, usando los objetos de ADO.net accedemos a la base de datos, y extraemos datos, los cuales serán tratados con OleDbDataReader.

Haciendo un símil con PHP, el OleDbCommand equivaldría al mysq_query(), mientras que el OleDbDataReader equivaldría al mysq_fetch_array().


Diseño de consultas

El siguiente paso es diseñar todas las consultas que nos pudieran hacer falta. Aquí enumeraré unas cuantas imprescindibles:


  • Comprobar si existe un usuario
  • Crear un nuevo usuario
  • Insertar un registro
Tal como quedó el modelo relacional, definiríamos las sentencias así:

  • select count(*) from usuario where nick='';
  • insert into email(email) values(''); insert into usuario(nick, nombre, apellido1, apellido2, idE, password) values('', '', '', '', select max(idE) from email, '');
  • insert into estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks) values('', '', '', '', '', '', '', ''); insert into juego(nick, id_estadistica, fecha) values('', select max(id_estadistica) from estadistica, '');

Desde luego estas consultas son las realmente básicas. No he puesto ningún dato porque de momento aún tenemos que ver cómo rellenaremos estas sentencias.

NOTA: cometí un error (como no...) cuando describía las tablas: la columna "minas" sirve para almacenar el número de minas que el usuario tenía marcadas cuando el juego terminó.

Hacer que funcione

El último paso antes de finalizar esta entrada es conectar todo; tenemos el MSAccess, el VB.net y el ADO.net. Es el momento de conectarlo todo!

Para ello, el objeto OleDbConnection necesita lo que se denomina "cadena de conexión". Ésta es un String que contiene información parametrizada sobre cómo y con qué conectará el objeto.

La cadena de conexión de ADO.net para MSAccess es la siguiente:

Provider=Microsoft.ACE.OLEDB.12.0;Data Source=SRC;Persist Security Info=False;

Las partes en negrita son variables. SRC indica la ruta física donde está la base de datos, y False indica si la conexión ha de ser persistente (por defecto siempre a false con MSAccess).

Ahora abrimos nuestro proyecto de VB.net, y añadimos las siguientes líneas en BX_module:

    Public con As OleDbConnection
    Public cn As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + Application.StartupPath + "\BuscaminaX.accdb;Persist Security Info=False;"
    Public cmd As OleDbCommand

Aquí definimos los dos objetos fijos que usaremos para tratar nuestra base de datos. Dos anotaciones: seguramente tendréis que importar el dominio System.Data.OleDb. Para ello escribid al comienzo del módulo:

"Imports System.Data.OleDb"

Por otra parte, tenéis que copiar la base de datos "BuscaminaX" a la carpeta de la aplicación ("/bin/debug").

El siguiente paso es definir tres funciones globales para nuestra aplicación:

  • Una función de conexión
  • Una función de ejecución de SQL (insert, update, delete)
  • Una función de consulta SQL (select)
Las podemos definir así:

#Region "SQL FUNCTIONS"
    Public Sub Conectar()
        BX_module.con = New OleDbConnection(cn)
    End Sub

    Public Sub Lanzar(ByVal sql As String, ByRef r As OleDbDataReader)
        BX_module.con.Open()
        cmd = New OleDbCommand(sql, BX_module.con)
        r = cmd.ExecuteReader()
    End Sub

    Public Sub Ejecutar(ByVal sql As String)
        Dim command As New OleDbCommand(sql, con)

        Try
            command.Connection.Open()
        Catch ex As Exception
        End Try

        command.ExecuteNonQuery()
        command.Connection.Close()
        command.Dispose()
        command = Nothing

        con.Close()
    End Sub
#End Region

Vamos a analizar un poco el código:

 - Conectar() instancia un nuevo OleDbConnection usando la cadena de conexión "cn".

 - Lanzar(sql, r) abre la conexión, instancia un nuevo OleDbCommand con "sql" y "con", y rellena "r". Nótese que para que los cambios en "r" sean persistentes, pasamos la variable por referencia ("ByRef") y no por valor ("ByVal")

 - Ejecutar(sql) crea un nuevo OleDbCommand (ya que luego será destruído), y ejecuta la sentencia SQL pasada.

Para leer los datos que devuelve lanzar debemos hacer algo similar a PHP (por ejemplo). Concretamente:


Lanzar(ret, r)

Do While r.Read
    'cosas. Se accede por "r(n)", donde n es un entero mayor o igual que 0
 Loop

con.Close()

Y así es cómo accedemos a los datos desde VB.net.

El siguiente paso es hacer un sistema de registro para cuando empieza el juego. También (después) crearemos una pantalla con estadísticas.

Para la pantalla de inicio de sesión, crearemos una nueva "SplashScreen". La llamaremos "LogIn.vb". De nuevo la preparamos borrando todo el contenido, y colocamos varios campos rellenables; tal que así:

img2
Ahora debemos esquematizar la comprobación de datos. Para ello haremos lo siguiente, teniendo en cuenta que un usuario anónimo no tendrá password, mientras que uno registrado sí; y tomando como supuesto que el usuario pulse "next" (el otro caso lo vemos ahora)










SI nick NO vacío
    recoges datos de DB
SINO
    error
FIN

SI datos(pass) NO vacío
    SI pass vacío
       error
    SINO
        SI datos(pass) = pass
            ok!
        SINO
           error
    FIN
SINO
    ok!
FIN    

Se puede ver una gran cantidad de "IF". Ahora os explicaré lo que yo llamo "filtrar por return". Esta técnica quizás no sirva para acortar demasiado el código, pero sirve para evitar tantas identaciones.

El sistema es el siguiente: se supone el "peor" caso. Si se cumple salimos, sin más (terminamos el sub, retornamos un valor de control...).

En la siguiente línea, ya tenemos controlado el caso, por tanto no hace falta un "ELSE".

Aplicando este concepto, podemos hacer:

SI nick vacío
    error(SALIR)
FIN

SI datos(pass) NO vacío
  SI pass vacío
    error(SALIR)
  FIN
SINO
  SI datos(pass) NO = pass
    error
   FIN
FIN

sigue

El siguiente caso a contemplar es el de crear un nuevo usuario. Para ello los pasos a seguir son:

 - Comprobar si todos los datos están introducidos
 - En caso que lo estén, comprobar si existe el usuario registrado
 - En caso que no exista, introducimos los datos.

Crearemos dos funciones principales para sendas tareas. Podrían ser algo así:

#Region "LogIn"
    Public Function nextStep() As Boolean
        Dim r As OleDbDataReader
        Dim pass As String

        If LogIn.TextBox1.Text.Length = 0 Then
            Return False
        End If

        BX_module.Conectar()
        Lanzar("select nick, password from usuario where nick ='" + LogIn.TextBox1.Text.ToString + "'", r)
        r.Read()

        Try
            pass = r(1)
        Catch ex As Exception
            pass = ""
        End Try

        BX_module.con.Close()

        If pass <> "" Then
            If LogIn.TextBox2.Text.ToString = "" Then
                Return False
            ElseIf LogIn.TextBox2.Text.ToString <> pass Then
                Return False
            End If
        Else
            If pass <> LogIn.TextBox2.Text.ToString Then
                Return False
            End If
        End If

        Return True
    End Function

    Public Function newUser() As Boolean
        Dim r As OleDbDataReader
        Dim cont As Integer
        Dim idE As Integer

        If LogIn.TextBox3.Text = "" Or _
           LogIn.TextBox4.Text = "" Or _
           LogIn.TextBox5.Text = "" Or _
           LogIn.TextBox6.Text = "" Or _
           LogIn.TextBox7.Text = "" Then
            Return False
        End If

        BX_module.Conectar()
        Lanzar("select count(*) from usuario where nick ='" + LogIn.TextBox4.Text.ToString + "' and idE = (select idE from email where email = '" + LogIn.TextBox5.Text.ToString + "')", r)
        r.Read()

        Try
            cont = r(0)
        Catch ex As Exception
            cont = 0
        End Try

        BX_module.con.Close()

        If cont <> 0 Then
            Return False
        End If

        BX_module.Conectar()
        Lanzar("select max(idE) from email", r)
        r.Read()

        Try
            idE = r(0) + 1
        Catch ex As Exception
            idE = 1
        End Try

        BX_module.con.Close()
        Ejecutar("insert into email(idE, email) values(" + idE.ToString + ", '" + LogIn.TextBox5.Text.ToString + "')")
        BX_module.Conectar()
        Lanzar("select idE from email where email = '" + LogIn.TextBox5.Text.ToString + "'", r)
        r.Read()
        Ejecutar("insert into usuario([nick], [nombre], [apellido1], [apellido2], [idE], [password]) values('" + LogIn.TextBox4.Text.ToString + "', '" + LogIn.TextBox6.Text.ToString + "', '" + LogIn.TextBox7.Text.ToString + "', '" + LogIn.TextBox8.Text.ToString + "', " + r(0).ToString + ", '" + LogIn.TextBox3.Text.ToString + "')")
        BX_module.con.Close()
        Return True
    End Function
#End Region

Ahora viene enlazar los valores de retorno al módulo principal. Esto lo haremos en dos partes, de manera que:

 - Crearemos una variable pública en LogIn.vb, de manera que el resultado de la función se guardará ahí.
 - Mientras la variable anterior sea "false", mostraremos la pantalla principal.

Esto lo hacemos así:

a) LogIn.vb

    Public hand As Boolean = False

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.hand = BX_module.nextStep()
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Me.hand = BX_module.newUser()
    End Sub


b) BuscaminaX.vb -> BuscaminaX_onLoad

        Do
            LogIn.ShowDialog()
        Loop Until LogIn.hand


Con esto damos por terminada la parte de Programación en VB.net

Así, en la próxima entrada trataremos la gestión de consultas desde MSAccess.

Pido disculpas por la tardanza; repito que estuve MUY liado.

Espero poder seguir escribiendo más a menudo!

Saludos y,

¡Hasta la próxima!

NOTA: algunos retrasos

Buenas!

Estoy muy muy liado...  voy hasta arriba en el trabajo durante esta semana, y aún tengo que adelantar la parte de VB.net

No obstante intento sacar ratos libres para escribir. Tened paciencia, espero terminar la siguiente entrada pronto!

Saludos y

Hasta la próxima...

A buscar M!nas: MSAccess - SQL

Buenas!

Empezamos por fin la parte de programación. Esta sección ocupará tres entradas, en las cuales ampliaremos todo el proyecto.

Pues bien, empecemos ya mismo con la primera parte: el SQL.

La primera tarea que tenemos que hacer es crear algunas sentencias SQL para crear las tablas, partiendo del modelo normalizado de la anterior entrada (lo siento, se me pasó un error; éste es el modelo bueno):


usuario(nick, nombre, apellido1, apellido2, idE, password) 
email(idE, email)
estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks, id_estadistica)
juego(nick, id_estadistica, fecha)

CREATE TABLE usuario(
    nick varchar(50),
    nombre varchar(50),
    apellido1 varchar(50),
    apellido2 varchar(50),
    idE int,
    password varchar(16)
);

CREATE TABLE email(
    idE int,
    email varchar(100)
);

CREATE TABLE estadistica(
    gana int,
    tiempo int,
    dificultad int,
    opcion int,
    autenticacion int,
    minas int,
    clicks int,
    id_estadistica int
);

CREATE TABLE juego(
    nick varchar(50),
    id_estadistica int,
    fecha varchar(14)
);

He querido hacer la parte de creación desde SQL, y dejar la parte de las restricciones. Esta parte la veremos con MSAccess directamente (así variamos un poco las cosas).

Pues bien, vamos a crear nuestra base de datos.

Primero abrimos MSAccess, seleccionamos "Nueva base de datos en blanco", le cambiamos el nombre (yo le pondré "BuscaminaX"), y apretamos "enter" o le damos a "crear" (img1).

img1
Ahora tendremos una tabla por defecto, tabla1. De momento no le prestamos atención.

Vamos a la sección "Crear", y de ahí vamos a "Diseño de consulta" (img2).

Nos saldrá una ventana nueva y una ventana emergente. Cerramos la ventana emergente y pulsamos, en el menú, la opción "SQL" (img3).

img2
Borramos el contenido ("SELECT;") y copiamos, una por una, las sentencias de creación. Tras escribir una sentencia pulsamos el botón de ejecutar. Esto hará que se creen las tablas.

img3
Una vez ejecutadas todas las sentencias deberemos tener algo similar a la "img4".

La siguiente tarea es asignar las PK. Para ello pulsamos en una tabla, y se nos abrirá el editor. Vamos a la pestaña inicio y pulsamos el icono "ver". Seleccionamos los campos necesarios y pulsamos la opción "Clave principal (img5). Repetimos esto para todas las tablas, y ya tendremos nuestras PK.

img4
img5
img6
Finalmente nos falta establecer las FK. Para ello vamos a la sección "Herraminentas de base de datos" y pulsamos sobre "Relaciones". Esto nos abrirá una nueva ventana con una nueva ventana emergente. Seleccionamos todas las tablas y le damos a intro (o a agregar). Veremos cómo aparecen en la ventana; hecho esto cerramos la ventana emergente, y nos quedará algo como la img6.

Ahora arrastramos los campos: de PK a FK (por ejemplo, de email.idE a usuario.idE). Recordad que debéis cerrar y guardar el resto de ventanas (MSAccess nos dará la lata continuamente con esto).

Al intentar crear una FK nos saldrá un cuadro; revisamos que los atributos sean los correctos, y marcamos "Exigir integridad referencial" (img7).


img7














Cuando todas las relaciones estén completadas, nos quedará el panorama como en la img8.

img8




















Siento la ingente cantidad de fotos, la verdad es que no sabía muy bien como cuadrarlas...

Pero bueno, creo que no queda tan mal :-P

Hemos terminado la parte de SQL (por ahora). Solo tenemos que guardar nuestra base de datos y podemos cerrar MSAccess hasta la entrega de gestión (dentro de dos entregas).

En la próxima veremos cómo ampliamos nuestro juego de VB.net para hacer que todo esto sirva para algo.

¡Hasta la próxima!














A buscar M!nas: MSAccess - normalización

Buenas!

Nos adentramos de lleno en la fase final de la construcción de nuestra base de datos primitiva.

Así, hoy veremos el paso final antes de implementar nuestro modelo; la normalización.

Este proceso, como su nombre indica, "normaliza" el modelo relacional, de manera que será más definido y útil.

El proceso es gradual, es decir, no se puede llegar a una forma normal (FN) si no está en la FN anterior (y así recursivamente...)

Conceptos previos:

Antes de entrar en el proceso, vamos a definir unos conceptos, que nunca viene mal:

  • O: durante esta entrada, para referirnos a un conjunto de valores originales usaremos la letra "o" mayúscula (no confundir con cero).
  • I: se trata de un conjunto imagen.
  • Intención: es la descripción "fija" de una tabla. Contiene los descriptores de la tabla así como las restricciones. Se puede representar como R(A1, A2, A3, ... , An)
  • Extensión: es el conjunto de tuplas ("filas") de una tabla en un momento determinado.


Ahora que tenemos los términos básicos definidos, podemos pasar a definir qué es una dependencia funcional:


  • Dependencia funcional: Restricción sobre una relación con intención R(A1, A2, A3, ... , An) que representa un esquema {x} -> {y} donde {x} e {y} son subconjuntos de la intención que garantiza que dado un valor de {x}, es determinado de manera única un valor de {y}*.

* Esto se puede representar (de un modo aproximado) como;

[{x}, {y} c (A1, A2, A3, ... , An) | Xi <-> Yj]


Vista esta pequeña introducción, podemos pasar a la normalización:

Normalización:

Como comentaba, se trata de un proceso progresivo. De esta manera, empezaré con la primera forma normal (1FN) e iré avanzando hacia modelos más normalizados. Empecemos:

  • 1FN: se dice que una relación está en 1FN si ningún atributo de la relación es en si mismo una relación, es decir, si todo atributo de la relación es atómico, no descomponible y no es un grupo repetitivo (solo tiene ciertos valores)
Ejemplificando: supongamos la siguiente tabla: Alumno(DNI, nombre, notas). En este caso, las notas son algo no atómico, descomponible y tiene parte de grupo repetitivo. Ampliando la información, sería:

 - No atómico: "notas" es un registro que puede estar repetido dentro de un mismo registro. Por ejemplo para el DNI1 puede haber algo así como "castellano primer trimestre: 5, inglés primer trimestre..." dentro del mismo registro.

 - Descomponible: se puede dividir en varias secciones. Por ejemplo: nota, asignatura, trimestre.

 - Grupo repetitivo: las asignaturas, la nota y el trimestre son de por sí grupos repetitivos.

Alumno(DNI, nombre, notas) ==> Alumno(DNI, nombre, asignatura, nota, trimestre)

Al normalizar se ha tenido que expandir la PK, para que no haya duplicados.
  • 2FN: se dice que una relación está en 2FN si está en 1FN y todo atributo no clave depende funcionalmente, en forma completa de la PK.
Esto quiere decir que todo aquel atributo que dependa de algo que no sea la TOTALIDAD de la PK de la tabla tendrá que ser modificado, de manera que ese atributo pasará a ser una tabla. La tabla que fue normalizada incorporará como FK la PK de la nueva tabla.

  • 3FN: se dice que una relación está en 3FN si está en 2FN y ningún atributo no clave depende funcionalmente de ningún otro conjunto de atributos no clave.
¿Qué significa esto? Puede parecer algo lioso, pero de vez en cuando se ve. Veamos un ejemplo:

Direccion(ID, calle, ciudad, provincia)

En este caso (y refiriéndonos a un modelo local, es decir, suponiendo que solo se tiene en cuenta un país) sabiendo la ciudad se sabe la provincia. Por eso, esta tabla no está en 3FN.

Direccion(ID, calle, ciudad, provincia) ==> Direccion(ID, calle, idCiudad)  Ciudad(ciudad, provincia)

Se crea una nueva tabla y se asigna una nueva FK


  • FNBC: esta forma normal es "especial", ya que está a caballo entre la 3FN y la 4FN. Normalmente se acepta una base de datos normalizada hasta la FNBC. No obstante nosotros veremos hasta la 5FN. 
La FNBC dice que dada una dependencia funcional {x} -> {y}, todo elemento de "x" es considerado como clave candidata.

Una definición así cuesta ver, así que dejo un ejemplo:

Notas(DNI, codAsig, codMatr, nota)

En esta tabla, DNI y codAsig son la PK. No obstante, el atributo "codMatr" es una clave candidata (es decir, podría servir como PK). Así, surgen cuatro opciones para normalizar esta situación:

a) Notas(DNI, codAsig, nota)
    Alumno(DNI, codMatr)

b) Notas(DNI, codAsig, nota)
    Alumno(codMat, DNI)

c) Notas(DNI, codAsig, nota)
    Alumno(codMat, DNI)

d) Notas(DNI, codAsig, nota)
    Alumno(DNI, codMat)


  • 4FN: para saber si una relación está en 4FN tenemos que comprobar que no existan DMI (Dependencia Multievaluada Independiente) y está en FNBC.
Una DMI se define como:

Sea "R" una relación con esquema R(A1, A2, A3, ..., An), y siendo {x}, {y} y {z} atributos de "R", se dará la DMI {x} ->> {y} si y solo si el conjunto de valores posibles de {y} para un par {x, z} depende únicamente del valor de "x" y es independiente del valor de "z".

Visto desde el punto de vista relacional, significa simplemente que las relaciones "n-arias" pasan a ser "n" relaciones con relación "n : n".

  • 5FN: una relación está en 5FN si y solo si está en 4FN y cumple que no tiene PK descomponible.
Para verlo mejor, un ejemplo:

Profesor(ID, nombre)
Asignatura(ID, nombre)
Centro(ID, nombre)

Ensenanza(IdPro, IdAsi, IdCen)  ==> PA(IdPro, IdAsig) PC(IdPro, IdCen)

Ahora ya sabemos en qué consiste normalizar; vamos a aplicarlo a nuestro modelo:

usuario(nick, nombre, apellido1, apellido2, email, password)
estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks, id_estadistica)
juego(nick, id_estadistica, fecha)


  •  1FN: en la tabla estadistica tenemos varios grupos repetitivos: "gana", "dificultad", "opcion", "autenticacion", "minas"). A continuación se describen los grupos repetitivos:
 - Gana:
   * Sí (1)
   * No (2)

 - Dificultad:
   * Fácil (1)
   * Medio (2)
   * Difícil (3)

- Opción:
   * Opción 1 (1)
   * Opción 2 (2)

 - Autenticación:
   * Registrado (1)
   * Anónimo (2)

 - Minas:
   * 10 (1)
   * 40 (2)
   * 99 (3)

Para deshacer los grupos repetitivos trasladamos todos los valores a numéricos, empezando siempre por 1 y llegando hasta el último valor disponible. Éstos valores se colocan arriba entre paréntesis.
  • 2FN: El modelo está en 2FN.
  • 3FN: Se puede apreciar en la tabla usuario cómo el campo "email", si no es nulo sirve para identificar a un usuario. Por ello realizamos la siguiente modificación:


usuario(nick, nombre, apellido1, apellido2, email, password) ==> usuario(nick, nombre, apellido1, apellido2, idE, password) email(idE, email)

  • FNBC: Se ha eliminado la clave candidata (email) en la tabla usuario (realmente no era clave candidata puesto que podría ser un dato vacío). Por tanto, estamos en FNBC.
  • 4FN: Está en 4FN
  • 5FN: Está en 5FN.
De este modo, tenemos por fin nuestro modelo relacional normalizado, siendo el siguiente:

usuario(nick, nombre, apellido1, apellido2, idE, password) 
email(idE, email)
estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks, id_estadistica)
juego(nick, id_estadistica, fecha)

Con esto dejamos la base preparada para el próximo paso: la programación.

Así, en la próxima entrega veremos cómo pasar este esquema al SQL, y más adelante haremos las ampliaciones necesarias en nuestro juego de VB.net.

Espero no se os haya hecho muy pesada la lectura.

¡Hasta la próxima!

A buscar M!nas: MSAccess - modelo relacional

Buenas!

Entramos de lleno ya en el tema del diseño. Para diseñar una buena base de datos, partiendo del modelo E - R expuesto en la entrada anterior, necesitamos realizar un proceso de "relacionalización".

Y, ¿En qué consiste? Básicamente se trata de "pasar" las tablas a notación relacional (una sintaxis más cercana al SQL).

Pero, sin embargo, debemos (o deberíamos) aplicar una serie de normas y patrones antes y después de hacer la transformación. Aplicarlas sirve para preparar la futura base de datos para que sea más sencilla de comprender, y a la larga que todo sea más fácil e intuitivo.

PRETECAR

A los pasos previos a la creación del modelo relacional las conozco como PRETECAR (es un acrónimo de Previa REgla de Transformación del Esquema Conceptual A Relacional).

De estas reglas hay dos (PRETECAR 1 y PRETECAR 2). A saber:
  • Eliminación de atributos múltiples
  • Eliminación de atributos compuestos
La primera casi nunca tendremos que aplicarla, mientras que la segunda es más usual tener que aplicarla. Explico más a fondo las reglas:

Un atributo múltiple es aquel que puede tener más de un valor. Es decir, un atributo que pueda ser tomado como lista o array.

Un ejemplo sería el caso en que tenemos la siguiente tabla:

LIBRO

ISBN
Título
Autor

En este caso,  un libro puede estar escrito por varios autores. Así, deberíamos aplicar la PRETECAR 1.

Un atributo compuesto es todo aquel que pueda ser divisible, como por ejemplo "Dirección", "Nombre completo"...

Ahora ya sabemos cuál es el problema que eliminan las PRETACAR 1 y 2. Pero falta saber cómo lo hacen:


  • PRETECAR 1: Extrapolamos el atributo múltiple a una entidad débil por existencia, dependiente de la clase de la que se segrega. Ambas clases guardarán una relación "n : n".
  • PRETECAR 2: Se crean los atributos que fueren necesarios, y se vuelve a comprobar la PRETECAR 2 (a veces los elementos compuestos tienen "dentro" más elementos compuestos).
Una pequeña aclaración: una entidad débil por existencia es aquella que depende de otra, pero tiene "sentido" que exista de por sí. Una entidad débil por existencia es, en el caso anterior (LIBRO), Autor, ya que es un atributo múltilpe, y por PRETECAR 1 sería una entidad débil por existencia.

Como se ve, el término "Autor" y lo que ello representa tiene significado; pero en este caso está supeditado a la clase LIBRO.

El otro caso de entidad débil (entidad débil por identificación) es aquella que depende de la entidad fuerte para ser un ente. Es el caso de la relación "Factura - Línea". En este caso, "Línea" sería la entidad débil, y no tiene razón de ser si no se relaciona con una factura.

RETECAR

El siguiente paso, tras preparar nuestro modelo E - R para pasar a modelo relacional, es hacerlo mediante las llamadas RETECAR. Son sencillas reglas que permiten que el paso a modelo relacional sea estándar y rápido. Son:

  • RETECAR 1: Todas las entidades presentes en el esquema conceptual se transforman en relaciones en el esquema relacional, manteniendo el número y tipo de atributos así como el identificador.
  • RETECAR 2: Se divide en tres opciones:
    • RETECAR 2.1: Si en una relación binaria el grado es "1 : 1" y ambas son obligatorias, entonces, se procede:
      • RETECAR 2.1.1: Si ambas tienen el mismo identificador se creará una sola tabla formada por la agregación de los atributos de ambas entidades, siendo la PK el identificador común.
      • RETECAR 2.1.2: Si ambas tienen identificadores diferentes, cada entidad se transformará en una tabla, usando la RETECAR 1, y cada tabla tendrá como PK el identificador de la propia entidad, y como FK la PK de la otra tabla.
    • RETECAR 2.2: Si en la relación binaria "1 : 1" hay una entidad obligatoria y la otra opcional, cada entidad se transformará en una tabla usando la RETECAR 1, y adicionalmente se procederá por una de estas dos vías:
      • RETACAR 2.2.1: El identificador de la opcional pasa como FK a la entidad obligatoria
      • RETECAR 2.2.2: Se construye una nueva tabla correspondiente a la relación formada por los atributos identificadores de las dos entidades y siendo la PK el identificador de la entidad opcional.
    • RETECAR 2.3: Si ambas entidades son opcionales, se crean sendas tablas por RETECAR 1, añadiendo una de estas dos posibilidades:
      • RETECAR 2.3.1: Los id. de cada entidad pasan a formar parte como FK de la otra tabla.
      • RETECAR 2.3.2: Se construye una nueva tabla correspondiente a la relación cuyos atributos serán los identificadores de las dos entidades, y la PK será uno de los dos identificadores de la tabla.
  • RETECAR 3: Se divide en dos opciones:
    • RETECAR 3.1: Si es una relación binaria de grado "1: n" o "n : 1", ambas entidades participan obligatoriamente o la entidad de grado "n" participa de manera opcional, cada entidad se transformará en una tabla por RETECAR 1, y el identificador de la entidad de grado "1" pasará a ser FK de la tabla de grado "n"
    • RETECAR 3.2: Si es una relación binaria de grado "1: n" o "n : 1", siendo ambas entidades opcionales o solamente la de grado "1", cada entidad se transforma por RETECAR 1, y se genera una nueva tabla correspondiente a la relación formada por los atributos identificadores de ambas tablas y los atributos de la relación.
  • RETECAR 4: En una relación binaria "n : n", o cualquier relación "n-aria", cada entidad pasa a ser una tabla, por RETECAR 1, y adicionalmente se genera una tabla para representar la relación. Esta nueva tabla estará formada por las PK de las entidades y los atributos de la relación, siendo la PK la agregación de las PK de las dos entidades.
  • RETECAR 5: En una relación jerárquica, se desestimará la entidad supertipo, transfiriendo todos los atributos de ésta a cada una de las entidades subtipo. Las relaciones que tenía la entidad supertipo pasarán a ser consideradas por cada entidad subtipo.
  • RETECAR 6: Se desestimarán las entidades subtipo, transfiriéndose todos los atributos de éstas a la entidad supertipo, así como cada una de las relaciones que las entidades subtipo mantenían
  • RETECAR 7: La relación jerárquica se transformará en tantas relaciones "1 : 1" como entidades subtipo estén presente.
Nota: De las tres últimas RETECAR (5, 6, y 7) solo se aplica una por cada relación jerárquica, dependiendo de lo que el analista vea conveniente.

Con esto termina la teoría. Es el momento de aplicar estos pasos a nuestro prototipo de modelo E - R:

Para realizar el proceso, primero aplicaré las dos PRETECAR, y después usaré las reglas para usar las RETECAR.

a) PRETECAR:

 - Cambiamos el atributo "Apellidos" por dos: "apellido1" y "apellido2" -> PRETECAR 2.

Hasta aquí va todo bien. El modelo está preparado para ser transformado. Pero antes una anotación: es muy usual juntar los atributos de apellido (al igual que de nombre) en uno solo, pues hay gente que tiene un apellido, hay gente que tiene dos... y lo mismo con los nombres.

Yo soy partidario de separarlos siempre que sea posible (es decir, que no resulte "molesto"). En este caso irá bien separarlos, pero cuando pidamos los datos tendremos que tener en cuenta que deberemos pedir los apellidos por separado.

Ahora que está todo preparado, aplicamos a ambas entidades la RETECAR 1, quedando así:

usuario(nick, nombre, apellido1, apellido2, email, password)
estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks, id_estadistica)

En la entrada anterior dejamos ver que la relación era "1 : n", por lo que tenemos que aplicar la RETECAR 3. Del mismo modo, y como hay un atributo de relación (aunque no lo especifiqué), procederemos a usar la RETECAR 3.2.

Entonces, quedaría así:

usuario(nick, nombre, apellido1, apellido2, email, password)
estadistica(gana, tiempo, dificultad, opcion, autenticacion, minas, clicks, id_estadistica)
juego(nick, id_estadistica, fecha)

Leyenda:

  • Negrita y cursiva: nombre tabla
  • Subrayado: clave primaria (PK)
  • Cursiva: clave foránea (FK)
  • Negrita y subrayado: clave primaria y clave foránea (PK/FK)
Finalmente, hacer un par de anotaciones: he añadido un atributo (id_estadistica) para poder distinguir todos los registros entre ellos. También, como he dicho antes, olvidé mencionar la fecha, pero es algo que no es obligatorio; sin embargo da mucho más juego y utilidad tenerlo.

Bien, de momento tenemos el modelo relacional. En la próxima entrega lo normalizaremos. Aunque vamos a intentar normalizarlo hasta la quinta forma normal (5FN), lo normal es hacerlo hasta la forma normal de Boyce-Codd (FNBC).

Y, con esta reflexión, os dejo.

¡Hasta la próxima!