Noticias Weblogs Código

Poesía Binaria

Usando SQLite en nuestros programas en C/C++ (II): Nueva interfaz v2 y prepared statements

April 27, 2015 08:37 AM

Hace unos días empezamos a programar utilizando SQLite para gestionar nuestra información usando SQL de toda la vida.

Bien, SQLite tiene la interfaz clásica, que vimos en el post anterior: sqlite3_open(), sqlite3_close(), sqlite3_exec()… con utilidades básicas para trabajar.

Por un lado, podemos tener más control sobre la base de datos, por ejemplo, podemos definir cómo abirmos la base de datos, tenemos códigos de error extendidos, ventajas con respecto al tratamiento interno de la memoria y algunas cosas más. La utilización es muy parecida.

Prepared statements con SQLite

Por otro lado, el enfoque con callbacks está muy bien, pero en ocasiones necesitamos el resultado de un sqlite3_exec() inmediatamente, justo debajo de esa línea, sin que tengamos que pasar contextos a una función y cambiar nuestra manera de pensar, es decir, hago una query y debajo tengo el resultado. Vamos a utilizar prepared statements con SQLite:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

int panic(char *error, int code)
{
  fprintf(stderr, "Error (%d): %s\n", code, error);
  exit(-1);
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   sqlite3_stmt *query;
   char *error = 0;
   int res;
   char *sql;
   int i;

   if ( (res=sqlite3_initialize()) != SQLITE_OK)
     panic("No se puede inicializar SQLite", res);

/* Abre la base de datos como sólo lectura, ver constantes SQLITE_OPEN_* para más info. */
   if ( (res=sqlite3_open_v2("test.db",  &db, SQLITE_OPEN_READONLY, NULL) )!= SQLITE_OK)
     panic("No puedo abrir la base de datos", res);

/* Prepara la sonsulta SQL */
   if ( (res=sqlite3_prepare_v2(db, "SELECT * FROM events", -1, &query, NULL) )!= SQLITE_OK)
     panic("No puedo ejecutar la consulta", res);

   while ( (res = sqlite3_step(query)) == SQLITE_ROW)
     {
       printf ("Filas encontradas: %d\n", sqlite3_data_count(query));
       for (i=0; i< sqlite3_column_count(query); ++i)
     {
       printf ("%s (%s) (Type: %d) => (%d bytes) %s\n",
           sqlite3_column_name(query, i),
           sqlite3_column_decltype(query, i),
           sqlite3_column_type(query, i),
           sqlite3_column_bytes(query, i),
           sqlite3_column_text(query, i));
     }
       printf("\n");
     }
   /* Finaliza la consulta y realiza limpieza */
   sqlite3_finalize(query);

   sqlite3_close_v2(db);

   /* Open database */
   return 0;
}

Aquí vemos cómo podemos lanzar la SELECT y obtener debajo el resultado, con alguna información adicional (para conocer algunas funciones más de SQLite), para ello tendremos:

  • sqlite3_step(sqlite3_stmt*) : Itera entre los resultados devueltos en la consulta. Si tenemos una consulta que devuelve 4 resultados, tendremos que llamar a esta función 4 veces, cada vez podrá extraer los datos de una fila. Si todo va bien devuelve SQLITE_ROW, si no hay más filas, SQLITE_DONE y otra cosa en caso de error.
  • sqlite3_data_count(sqlite3_stmt*) : Nos devuelve el número de filas. Siempre y cuando hayamos hecho un sqlite3_step() antes.
  • sqlite3_column_count(sqlite3_stmt*) : Devuelve el número de columnas que hay en la fila actual
  • sqlite3_column_name(sqlite3_stmt*, int index) : Devuelve el nombre de la columna número index
  • sqlite3_column_decltype(sqlite3_stmt*, int) : Devuelve el tipo de dato exacto de la columna especificada. Aunque en SQLite tenemos sólo 5 tipos de dato (NULL, INT, FLOAT, BLOB, TEXT), hay datos derivados mucho más complejos, por ejemplo DATETIME para fecha y hora, que convierte directamente a TEXT.
  • sqlite3_column_type(sqlite3_stmt*, int) : Devuelve el tipo de dato de SQLite para la columna dada, (SQLITE_INTEGER, SQLITE_FLOAT, SQLITE_TEXT, SQLITE_BLOB, SQLITE_NULL)
  • sqlite3_column_bytes(sqlite3_stmt*, int) : Devuelve la longitud en bytes del dato de la columna (como si fuera un string)
  • sqlite3_column_text(sqlite3_stmt*, int) : Devuelve el dato de la columna especificada en forma de cadena de caracteres (char*))

Escogiendo el tipo de variable correcto en C

Anteriormente hemos visto cómo los valores devueltos por SQLite se convierten a string (todos son convertibles), y podemos verlos en pantalla. Aunque a veces, seguro que no nos interesa eso, si pedimos un número a SQLite, lo queremos en forma de número, sin necesidad de transformarlo luego. Con este segundo ejemplo, vemos que dependiendo del valor devuelto por sqlite3_column_type() extraemos el valor con uno u otro tipo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

int panic(char *error, int code)
{
  fprintf(stderr, "Error (%d): %s\n", code, error);
  exit(-1);
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   sqlite3_stmt *query;
   char *error = 0;
   int res;
   char *sql;
   int i;

   if ( (res=sqlite3_initialize()) != SQLITE_OK)
     panic("No se puede inicializar SQLite", res);

   if ( (res=sqlite3_open_v2("test.db",  &db, SQLITE_OPEN_READONLY, NULL) )!= SQLITE_OK)
     panic("No puedo abrir la base de datos", res);

   if ( (res=sqlite3_prepare_v2(db, "SELECT * FROM events", -1, &query, NULL) )!= SQLITE_OK)
     panic("No puedo ejecutar la consulta", res);

   while ( (res = sqlite3_step(query)) == SQLITE_ROW)
     {
       printf ("Filas encontradas: %d\n", sqlite3_data_count(query));
       for (i=0; i< sqlite3_column_count(query); ++i)
     {
       printf ("%s (%s) (Type: %d) => (%d bytes)",
           sqlite3_column_name(query, i),
           sqlite3_column_decltype(query, i),
           sqlite3_column_type(query, i),
           sqlite3_column_bytes(query, i));
       switch (sqlite3_column_type(query, i))
         {
         case SQLITE_INTEGER:
           printf ("%d", sqlite3_column_int(query,i));
           break;
         case SQLITE_FLOAT:
           printf ("%lf", sqlite3_column_double(query,i));
           break;
         case SQLITE_BLOB:
           printf ("BINARIO");
           break;
         case SQLITE_TEXT:
           printf ("%s", sqlite3_column_text(query,i));
           break;
         case SQLITE_NULL:
           printf ("NULL");
           break;
         default:
           printf ("Not supported"); /* No deberíamos entrar nunca */
         }
       printf("\n");
     }
       printf("\n");
     }
   /* query cleanup */
   sqlite3_finalize(query);

   sqlite3_close_v2(db);

   /* Open database */
   return 0;
}

Vinculando argumentos (binding arguments)

Además de la precompilación de las consultas que vamos a utilizar para poder ejecutarlas más rápido (sobre todo si ejecutamos la consulta repetidas veces), una de las ventajas de los prepared statements es que nos permiten vincular argumentos de forma segura en una consulta. Siempre hay caracteres que no se pueden pasar en un sistema, cuando los argumentos son de tipo TEXT, si metemos una comilla entre el texto podemos cerrar la query y puede que no queramos eso. También puede ser utilizado por usuarios malintencionados para romper nuestros programas. Y bueno, también nos vale para tratar todos los argumentos que pasamos a SQLite de la misma forma, y olvidarnos de poner comillas en los textos, dejar los números sin ellas y poner bien los NULL, vamos a hacer una pequeña consulta con parámetros sobre el mismo programa de antes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <stdlib.h>
#include "sqlite3.h"

int panic(char *error, int code)
{
  fprintf(stderr, "Error (%d): %s\n", code, error);
  exit(-1);
}

int main(int argc, char* argv[])
{
   sqlite3 *db;
   sqlite3_stmt *query;
   char *error = 0;
   int res;
   char *sql;
   int i;

   if ( (res=sqlite3_initialize()) != SQLITE_OK)
     panic("No se puede inicializar SQLite", res);

   if ( (res=sqlite3_open_v2("test.db",  &db, SQLITE_OPEN_READONLY, NULL) )!= SQLITE_OK)
     panic("No puedo abrir la base de datos", res);

   if ( (res=sqlite3_prepare_v2(db, "SELECT * FROM events WHERE timestamp>? AND timestamp<? AND level>? AND message LIKE ?", -1, &query, NULL) )!= SQLITE_OK)
     panic("No puedo ejecutar la consulta", res);

   printf("Tengo que vincular %d parámetros\n", sqlite3_bind_parameter_count(query));

   if ( (res=sqlite3_bind_text(query, 1, "2015-01-01", -1, SQLITE_STATIC)) )
     panic("No puedo vincular el argumento 1", res);

   if ( (res=sqlite3_bind_text(query, 2, "2015-04-01", -1, SQLITE_STATIC)) )
     panic("No puedo vincular el argumento 2", res);

   if ( (res=sqlite3_bind_int(query, 3, 12) ) )
     panic("No puedo vincular el argumento 3", res);

   if ( (res=sqlite3_bind_text(query, 4, "%again%", -1, SQLITE_STATIC)) )
     panic("No puedo vincular el argumento 4", res);

   while ( (res = sqlite3_step(query)) == SQLITE_ROW)
     {
       printf ("Filas encontradas: %d\n", sqlite3_data_count(query));
       for (i=0; i< sqlite3_column_count(query); ++i)
     {
       printf ("%s (%s) (Type: %d) => (%d bytes)",
           sqlite3_column_name(query, i),
           sqlite3_column_decltype(query, i),
           sqlite3_column_type(query, i),
           sqlite3_column_bytes(query, i));
       switch (sqlite3_column_type(query, i))
         {
         case SQLITE_INTEGER:
           printf ("%d", sqlite3_column_int(query,i));
           break;
         case SQLITE_FLOAT:
           printf ("%lf", sqlite3_column_double(query,i));
           break;
         case SQLITE_BLOB:
           printf ("BINARIO");
           break;
         case SQLITE_TEXT:
           printf ("%s", sqlite3_column_text(query,i));
           break;
         case SQLITE_NULL:
           printf ("NULL");
           break;
         default:
           printf ("Not supported"); /* No deberíamos entrar nunca */
         }
       printf("\n");
     }
       printf("\n");
     }
   /* query cleanup */
   sqlite3_finalize(query);

   sqlite3_close_v2(db);

   /* Open database */
   return 0;
}

En este caso, vemos que hemos colocado interrogaciones en la query inicial, cada interrogación será sustituída por un valor que luego especificaremos con sqlite3_bind_xxxx(), en este caso, vamos a especificar rangos de fechas y un número.

sqlite3_bind_int() sólo necesita la query, la posición del parámetro que va a modificar (¡¡ojo!! El primero es el 1 y no el 0) y su valor.

sqlite3_bind_text() es un poco especial, son cadenas de caracteres, y sabemos que C es muy suyo para eso. Tenemos que pasarle:

  • La query, vamos el puntero al sqlite_stmt para el que queremos asignar el parámetro
  • El número de parámetro a vincular
  • La cadena que queremos vincular… hasta aquí vamos bien, es similar al sqlite_bind_int()
  • Tamaño de la cadena (por si tenemos un número exacto de caracteres), pero si no es así, ponemos un número negativo y cogerá hasta el primer terminador (\0) que encuentre.
  • SQLITE_STATIC o SQLITE_TRANSIENT, dependiendo de si el valor de la cadena que hemos pasado cambiará con el tiempo o no. Como el valor tenemos que conservarlo, imaginemos que usamos una variable para especificar la cadena, y dicha variable será sobreescrita en breve (puede que porque sea una variable temporal, o porque los sqlite3_bind_text() están dentro de una función y las cadenas son variables locales). Como aquí vemos que la cadena no cambia usamos SQLITE_STATIC, pero en caso de duda, mejor usamos SQLITE_TRANSIENT, hacemos que SQLite se haga una copia de la cadena, y nos curamos en salud.

SQLite y C++

Es cierto que todos los ejemplos que he puesto son para lenguaje C, sin ++, aunque podemos utilizarlo de forma muy parecida. De todas formas, seguro que los programadores de C++ agradecen tener una biblioteca que utilice esta base de datos a la manera C++ (the C++ way!), y que ahorre un poco de tiempo, y escritura.
Hay varias bibliotecas para utilizarlo, pero la única que he visto más o menos en desarrollo todavía es sqlite3pp (Al menos, actualizada en 2015).
En su github hay varios ejemplos interesantes.
Foto: Travis Warren (Flickr CC-by)

The post Usando SQLite en nuestros programas en C/C++ (II): Nueva interfaz v2 y prepared statements appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 196

April 27, 2015 07:15 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada, espero que os resulten interesantes :-)

.Net

ASP.NET

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

» Leer más, comentarios, etc...

Koalite

Principio de Segregación de Interfaces para Abuelas

April 27, 2015 05:06 AM

Hace un par de semanas escribía sobre lo que realmente significa el principio de inversión de independencias con el objetivo de intentar profundizar más allá de la implementación típica y poder ver en qué ideas se basa y dónde más podemos aplicar esas ideas.

Siguiendo con esa línea, en este post vamos a aprovechar para analizar el trasfondo del principio de segregación de interfaces (PDF), la I de SOLID, que seguramente sea uno de los principios de SOLID menos citados y menos tenidos en cuenta de los cinco.

abuela-preocupada

Segregación de interfaces para abuelas

Imagina que tu abuela quiere contratar una línea de teléfono fijo para hablar con sus amigas. Cuando va a hablar con la operadora de turno, encuentra una oferta en la que, por el mismo precio que una línea, le ofrecen un pack que incluye la línea de teléfono, internet y televisión por cable.

Aunque tu abuela sólo va a usar la línea, ya que le cuesta lo mismo una cosa que otra, decide contratar el pack. Total, así si un día quiere aprender eso del internet o ver algún programa en un canal de los raros, puede hacerlo.

Unas semanas más tarde, un día descubre que no puede llamar por teléfono a su amiga Puri para felicitarle por su cumpleaños. Parece ser que la línea de teléfono de su pack utiliza algo que se llama voz sobre ipé o algo así, y cuando no funciona el aparato rúter, no se puede llamar. Por suerte un simpático técnico de la operadora le cambia el rúter y le soluciona el problema, pero ya no consigue felicitar a tiempo a Puri en su cumpleaños (y a ciertas edades no sé sabe cuántas oportunidades quedan para ello).

Otro día, tampoco puede llamar a Dora para acercarse a visitarla. Una chica muy agradable de la operadora le explica que es que tienen que actualizar remotamente el finguar de su rúter para darle más megas del internet, y que mientras lo hacen no podrá conectarse y su voz sobre ipé no funcionará.

Estos problemas que ha tenido tu (hipotética) abuela, vienen motivados por violar el principio de segregación de interfaces.

Tu abuela sólo quería hablar por teléfono, pero ha adquirido una dependencia sobre algo mucho mayor, el pack internet+llamadas+televisión, por lo que cuando algo de ese pack falla, aunque sea algo que ella no utiliza para nada, se ve afectada por ello.

El enunciado formal

En el artículo que enlazaba antes, Robert C. Martin explica el principio de segregación de interfaces en detalle, pero no sé si es porque el artículo ha resistido mal el paso del tiempo o ese día el autor estaba poco inspirado, pero la argumentación resulta a veces un poco confusa y, el diseño final al que llega es, al menos desde mi punto de vista, bastante discutible.

Sin embargo, la idea de base es sencilla y bastante razonable: si tienes un componente “grande” que es consumido por varios clientes, y cada cliente utiliza sólo ciertas características del componente “grande”, ese cliente debería depender sólo de esas características. El enunciado formal es:

Los clientes no deben verse obligados a depender de interfaces que no utilizan.

Que traducido a lenguaje de abuelas sería:

No contrates cosas que no necesitas.

Es importante tener en cuenta que cuando hablamos de interfaces, no estamos (necesariamente) hablando de interfaces como los de Java o C#, sino del API que expone un objeto concreto. Tal vez un término más apropiado sería contratos, que es el que usaré en el resto de post para distinguir entre estos interface/APIs, y los interfaces de C#/Java.

El trasfondo de todo esto

¿Qué es lo malo de tener contratos grandes? A fin de cuentas, puede ser que estemos agrupando funcionalidad que conceptualmente esté relacionada y, a priori, tendría sentido mantenerla unida en aras de aumentar la cohesión. Además, puestos a incluir a una dependencia, mejor tener una que hace más cosas por si acaso en algún momento me hacen falta, ¿no?

El problema, como casi siempre, es el acoplamiento. La típica disyuntiva entre cohesión y acoplamiento que se produce al desarrollar software.

Si tenemos un contrato grande pero cada cliente utiliza una parte diferente, estamos acoplando implícitamente unos clientes con otros a través de ese contrato.

En el ejemplo de la abuela, el mismo contrato (el pack completo) sirve a clientes que sólo quieren llamar, como ella, y a otros que quieren navegar por internet. Para mejorar el servicio de los clientes que usan internet (darles más megas) hace falta cambiar la implementación (actualizar el finguar del rúter) y eso implica pérdida de servicio para clientes que, en principio, no tendrían motivos para verse afectados por ello.

Si lo llevamos a código, tendríamos algo como esto:

public interface IMegaPack {
    void MakePhoneCall();
    void ConnectToInternet();
    void WatchCableTV();
}

Es un único interfaz que expone toda la funcionalidad, por lo que obligamos a todos los clientes depender del interfaz completo. La solución es sencilla, podemos partir el interfaz en trozos más pequeños:

public interface IVoice
{
    void MakePhoneCall()
}

public interface IInternet
{
    void ConnectToInternet();
}

public interface ICableTV
{
    void WatchCableTV();
}

public interface IMegaPack : IVoice, IInternet, ICableTV
{
}

Es importante tener en cuenta que partir el interfaz no quiere decir que partamos su implementación. Técnicamente podríamos mantener un único objeto que implementa todos los interfaces y cada cliente lo vería sólo como la parte que le interesa.

Cuando se aplica esta idea de un único objeto que implementa varios interfaces específicos para cada caso de uso, a los interfaces se les suele llamar role interface.

Aunque la situación mejora porque los clientes no quedan acoplados a través del contrato, sí que siguen acoplados a través de la implementación (al final es el mismo objeto), por lo que la solución no es todo lo buena que a uno le gustaría. Dependiendo del caso, esto será más o menos problemático y solucionarlo será más o menos fácil (a veces existe un acoplamiento real entre las funcionalidades y no es sencillo evitarlo).

Otro problema adicional de depender de objetos grandes, es que cuanto mayor es el tamaño de un objeto más probable es que tenga más dependencias, por lo que los clientes estarán asumiendo transitivamente un número mayor de dependencias.

Al crear interfaces más pequeños, tenemos la ventaja adicional de que, si es necesario crear nuevas implementaciones del interfaz para un caso de uso concreto, no necesitaremos implementar también el resto de métodos que no están relacionados con ese caso de uso.

Llevando al extremo la segregación de interfaces, acabaríamos con intefaces degenerados que tienen un único método. Es razonable. En muchos lenguajes a esas cosas se les llaman funciones y a veces son la mejor solución, como decía John Carmack:

A veces, la implementación elegante es sólo una función. No un método. No una clase. No un framework. Sólo una función.

De contratos a conceptos

Si ampliamos un poco nuestros horizontes y dejamos de pensar en contratos como interfaces u objetos, veremos que hay ideas del principio de segregación se puede aplicar en más ámbitos.

Por ejemplo, es fácil abusar de un gestor de paquetes para añadir dependencias sobre un paquete que hace 1000 cosas cuando sólo necesitas 2.

Eso hará que tengamos que asumir como propias dependencias de ese paquete que, en realidad, no están relacionadas con las cosas que utilizamos.

También puede ocurrir con cosas que cuesta considerar interfaces/contratos.

Si tenemos un método que necesita obtener las ventas de un producto, ¿es mejor pasarle el objecto Product o sólo el id? Ya hablamos de eso hace tiempo pero si le pasas el objeto Product y sólo necesita el id, se introducirá una dependencia sobre un contrato mayor (toda la clase Product) por lo que quedará acoplado al resto de clientes de esa clase.

Aplicando el principio de segregación de interfaces, podríamos pensar que si ese método sólo necesita poder obtener un id, no debería quedar acoplado al contrato completo de Product, con su nombre, su precio y unas cuantas decenas de propiedades más.

Muchas veces al pensar en contratos e interfaces nos vamos inmediatamente a pensar en servicios, pero pasa lo mismo con conceptos más “tangibles” dentro de nuestras aplicaciones. Si parte de nuestro sistema sólo necesita ciertos datos y operaciones de un cliente, y otra parte del sistema necesita datos y operaciones diferentes, aunque en la vida real sea la misma entidad (la empresa cliente), seguramente sea buena idea separarlo en dos contratos distintos y, posiblemente, en dos implementaciones distintas también.

Conclusiones

En cuanto te alejas un poco del código, el principio de segregación de interfaces consiste, básicamente, en simplificar al máximo las dependencias entre componentes, haciéndolas lo más específicas y focalizadas posibles.

La principal ventaja de esto es que vamos a conseguir componentes menos acoplados ya que dependerán de roles más específicos, y eso nos facilitará evolucionarlos por separado y aumentará la flexibilidad del sistema.

Debemos tener en cuenta que si al final esos roles son implementados por un único objeto, aunque hayamos independizado los contratos seguiremos teniendo acoplamiento a través de la implementación. Si optamos por implementaciones separadas para cara rol, el riesgo que asumimos es acabar con un código poco cohesionado más complicado de enteder y mantener.

Como siempre, cada caso merece una consideración aparte, pero si aplicas el sentido cómun y comprendes en qué se fundamentan los principios que estás aplicando, podrás tomar mejores decisiones.

Fotografía por Natalia Rivera con licencia CC BY 2.0

Posts relacionados:

  1. Interfaces marcadoras, atributos y convenciones
  2. Interfaces + Extension Methods = Protocolos de Clojure

» Leer más, comentarios, etc...

Blog Bitix

Certificado SSL, de empresa, «wildcard» y de validación extendida

April 25, 2015 10:00 AM

Usar un protocolo seguro garantiza de que los datos intercambiados entre el cliente y el servidor no son leídos ni modificados por una tercera parte además de verificar que la comunicación se está realizando entre las partes que dicen ser. Para usar un protocolo seguro como SSL/TLS debemos disponer de con certificado, con OpenSSL podemos generar y convertirlo al formato que deseemos, sin embargo, para que el usuario tenga garantía de que el certificado es válido este se debe estar firmado por una autoridad de certificación (CA) en la que confíe, generalmente con una de las autoridades de certificación cuyos certificados están preinstalados en el navegador web (en Firefox podemos verlos en Preferencias > Avanzado > Certificados > Ver certificados), los certificados autofirmados son útiles para hacer pruebas pero no son válidos para los usuarios. En este artículo comentaré que tipos de certificados hay y donde podemos obtener o comprar un certificado digital firmado por una CA que sea de confianza para el usuario.

Los navegadores suelen indicar que se está usando una comunicación segura cuando en la barra de direcciones se muestra un candado y se está usando el protocolo https. Además, haciendo clic en el candado se pueden ver los detalles del certificado usado por el servidor para la comunicación cifrada.

Sin embargo, para proporcionar más seguridad y garantía de que como usuarios nos estamos comunicando con el servidor que creemos sin examinar el certificado algunos certificados permiten mostrar también en la barra de direcciones un recuadro verde con el nombre de la entidad, el recuadro verde que solemos ver también en la barra de direcciones al acceder a algunos dominios y que es proporcionado por certificados de validación extendida.

Por otra parte los certificados SSL se generan para un dominio en concreto con lo que en principio se debería comprar un certificado por cada dominio en el que deseemos usar una comunicación segura. Sin embargo, para evitar comprar múltiples certificados para los diferentes dominios o subdominios podemos comprar un certificado wildcard que nos servirá para los subdominios (*.ejemplo.com) o un certificado multidominio (ejemplo.com, ejemplo.net, …) para como su nombre indica varios dominios. En los certificados de empresa se solicitan datos datos adicionales al adquirirlo y en los detalles del certificado aparece el nombre de la empresa (campo Organización (O) como en el caso de GitHub).

Los certificados wildcard y que muestran el recuadro verde son más caros pero pueden ser útiles sobre todo para una página de comercio electrónico, el recuadro verde añade más seguridad, seguramente mejore los ratios de conversión y evite suplantaciones de identidad o phising. Además, utilizar un protocolo seguro es un nuevo criterio que utiliza el buscador Google en su algoritmo para establecer el posicionamiento en la página de resultados. Con las intrucciones que incorporan los procesadores modernos el cifrado y descifrado de los datos no tiene por que significar un aumento de carga considerable para el servidor ni el cliente ni en dispositivos móviles.

¿Cómo obtener un certificado SSL firmado por una entidad raíz de certificación? Las entidades de registro de dominios aparte de dominios, hosting virtual o privado algunos permiten comprar certificados SSL. Uno de los que conozco que permite comprar certificados SSL, de empresa, con recuadro verde o wildcard es DonDominio, otro es Arsys.

En el caso de DonDominio dependiendo de la entidad emisora del certficado que deseemos variará el precio, también si queremos que tenga validación extendida o sea wildcard. En el caso de un certificado SSL simple que valide solo el dominio es de unos 5 €, de validación de empresa unos 28 €, un certificado de validación extendida con recuadro verde desde unos 126 € y un certificado wildcard de desde unos 75 €. Estos son precios desde, diferentes opciones pueden salir bastante más caras y hay que tener en cuenta que son para una validez de una año, al igual que los dominios hay que renovar su uso.

Si no necesitamos el recuadro verde ni un certificado wildcard una opción interesante es obtener uno gratis a través de Lets Encrypt. Esta nueva entidad de certificación nos permitirá obtener uno sin coste, de forma sencilla y automatizada, detrás de esta entidad están organizaciones como Linux Foundation, Mozilla o CISCO.

Una vez obtenido el certificado debemos instalarlo en el servidor, en el artículo Configurar SSL en un servidor Tomcat JBoss, Wildfly, Lighttpd, nginx o Apache comento como usar un certificado en los principales servidores web y de aplicaciones. Si necesitamos un formato concreto podemos convertir el certificado con OpenSSL.

Referencia:
Generar y convertir claves y certificados con OpenSSL
Configurar SSL en un servidor Tomcat, JBoss, WildFly, Lighttpd, nginx o Apache
Qué es un certificado SSL y por qué debería importarte

» Leer más, comentarios, etc...

Blog Bitix

Nueva visita a 5+ opciones de «hosting» para aplicaciones

April 24, 2015 08:00 PM

Hace tres años escribí un artículo sobre varias opciones de hosting que disponemos para hospedar aplicaciones o páginas web. En ese artículo comentaba varias posibilidades desde un servidor propio usando una Raspberry Pi, proveedores de hosting, Amazon EC2, Google App Engine, Jelastic, OpenShift, AppFog, Cloud Foundry (VMWare), Heroku, Azure (Microsoft) y Google Compute (Google Cloud Platform). Pasado todo este tiempo en este artículo revisaré las opciones de hospedaje con algunas nuevas que en su momento no conocía, otras siguen siendo totalmente válidas.

Servidor propio

Si queremos una opción para algo simple y para nosotros mismos podemos utilizar un servidor propio usando como hardware por ejemplo una Raspberry Pi 2 Model B, con la segunda versión de este miniordenador que ahora tiene 4 núcleos y 1 GiB de memoria puede servirnos para cantidad de cosas interesantes. Además de la Raspberry Pi 2 hay multitud de dispositivos similares, en la página de Arch Linux ARM podemos ver los modelos soportados en esta distribución. Otro modelo destacado es la Cubox-i también con 4 núcleos y en el modelo más potente con 2 GiB de memoria aunque bastante más caro que la Raspberry Pi.

Uno de los usos para los que nos puede servir es para albergar con ownCluod tu información personal como archivos, fotos, calendarios, contactos pudiendo acceder desde cualquier dispositivo ya sea el ordenador personal, teléfono inteligente o dispositivo móvil. Su punto a favor es que tus datos están bajo tu control. Aunque esta opción es posible se puede optar por otras opciones que comento más adelante, uno de los motivos es que no es fiable el servicio que podemos ofrecer ya que depende la conexión a internet que podemos tener en nuestra casa y por los cortes de corriente que se pueden producir o los fallos en el hardware que puede provocar que perdamos los datos si no tenemos copias de seguridad.

Con esta opción tendremos un control total del software instalado sin ninguna limitación, sin embargo, si necesitamos escalar la aplicación tendremos más dificultades si necesitamos comprar hardware nuevo.

Raspberry Pi

Proveedor de hosting

La siguiente opción a considerar puede ser un servidor ofrecido por muchos registradores de dominios. Si el tráfico del servicio que planeamos ofrecer no es muy alto (y así serán en los inicios) es una opción adecuada. En la mayoría de las opciones de este tipo estaremos limitados en el lenguaje de programación que podremos usar generalmente PHP o la base de datos generalmente MySql.

Mucha gente usa esta opción para albergar su bitácora con WordPress que incluso para un tráfico considerable es suficiente, por supuesto es válida para las empresas que quieran tener presencia en internet aunque solo sea para incluir su dirección teléfono de contacto y una breve descripción y los productos que ofrece. Para estos usos el coste de esta opción puede estar entre 1€/mes y 20€/mes aparte del coste del dominio.

Hay multitud de proveedores algunos de los más conocidos son DonDominio, Arsys, Piensa Solutions, … pero ninguno de estos y en otros casos muy pocos ofrecen hosting para aplicaciones de la plataforma Java. No tendremos libertad en la tecnología que usamos ni siquiera en las versiones de la misma.

Amazon EC2, Azure, Google Cloud

Si la aplicación o proyecto crece las nubes de Amazon EC2, Azure y Google Cloud se adaptan a las necesidades que tengamos ahora y, mejor aún, en el futuro. Y si en un futuro es necesario nos proporcionan flexibilidad pudiendo ampliar o reducir los recursos consumidos. Son algo más caras que otras opciones pero por lo que ofrecen son buenas opciones, por ejemplo, Amazon EC2 ofrece varios servicios que enriquecen su oferta de infraestructura como servicio (IaaS, Infrastructure as a service). En estas opciones de IaaS tendremos gran control sobre el software que instalamos, deberemos tener en cuenta que los datos que maneja la aplicación estarán hospedados en los sistemas de la nube elegida.

En estas opciones IaaS tenemos libertad de elegir el lenguaje de programación que queremos emplear para en la aplicación ya sea Java, PHP, Python, C# o Ruby, … también tendremos libertad en la base de datos MySQL, PosgreSQL, Redis, … o en el servidor de aplicaciones o servidor web.

En Amazon EC2 el coste puede variar dependiendo de los recursos que reservemos, para una aplicación mediana una instancia t1.small con 2GiB de memoria reservada previamente y 50 GiB de espacio de disco SSD durante 3 años cuesta unos 332.00€ por reservar la instancia durante ese periodo y unos 2€ adicionales al mes, a esto deberemos sumar el coste del dominio. En la calculadora de Amazon EC2 podemos estimar el coste según los recursos que necesitemos.

Amazon Web Services Microsoft Azure Google Cloud

Linode, Digital Ocean

Algunas opciones totalmente válidas para muchos casos que también nos proporcionan flexibilidad son Linode y Digital Ocean, también entran dentro de la categoría de IaaS. El coste de los planes ofrecidos por cada una de estas es muy sencillo en Linode empieza desde los 10€/mes hasta los 80€/mes y en Digital Ocean desde los 5€/mes pasando por los 80€/mes hasta los 640€/mes. Salvo los planes de volúmenes altos de Digital Ocean los precios son similares a Linode según las características disponibles en ambos.

Estas opciones son totalmente válidas tanto para proyectos personales como un blog con WordPress como para proyectos profesionales. La nube de Amazon ofrece multitud de servicios que en algunos casos son útiles pero si no nos son necesarios las opciones comentadas en este apartado serán suficientes y algo más baratas.

Linode Digital Ocean

Otras

Hay otro tipo de opciones conocidas como plataforma como servicio (PaaS, Platform as a service) como OpenShift, AppFog, Cloud Foundry, Heroku. De entre estas destacaré OpenShift ya que proporciona una capa gratuita con la que tendremos lo que ellos denominan gears, nos ofrecen gratuitamente 3 con 512 MiB de memoria y 1 GiB de espacio en disco. Esta opción es la que he utilizado para construir Blog Stack, en el artículo Arquitectura y hospedaje de Blog Stack detallo técnicamente el proyecto en el que el único coste es el dominio (12€/año).

Notas finales

Las opciones son múltiples para hospedar nuestra aplicación. Si se trata de algo para uso personal una Raspberry Pi pueda valernos, si se trata de una web presencial estática que no requiera programación un proveedor de hosting será suficiente. Si queremos tener flexibilidad y más libertad en las herramientas del proyecto las nubes de Amazon, Azure o Google nos servirán. Si no necesitamos todos los servicios de los anteriores Linode o Digital Ocean ofrecen unos planes de precios muy sencillos y previsibles. Finalmente están los PaaS que permiten desentendernos de la infraestructura y centrarnos en la aplicación.

Referencia:
5 opciones de hosting para aplicaciones Java
Arquitectura y hospedaje de Blog Stack

» Leer más, comentarios, etc...

Poesía Binaria

Creando un modelo sencillo en Magento (paso a paso y con ejemplos)

April 21, 2015 08:51 AM

Anteriormente vimos cómo crear un plugin para Magento y cómo crear un controlador para Magento. Ahora le toca el turno al modelo. Intentaré poner con todo detalle todo el proceso.
Por eso, vamos a editar app/code/local/NuestraEmpresa/nuestroPlugin/etc/config.xml, en nuestro ejemplo app/code/local/Poesia/HolaMundo/etc/config.xml para indicar que vamos a crear modelos y las conexiones de base de datos que se deben utilizar para el acceso. He pegado el archivo entero, pero indico con un comentario las novedades:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?xml version="1.0" encoding="UTF-8"?>
<!--
Opcionalmente podemos poner un comentario contando qué hace nuestro módulo, nuestra web,
información sobre la licencia, etc
-->
<config>
    <modules>
        <Poesia_HolaMundo> <!-- namespace_modulo -->

            <!-- Esta es la versión de nuestro módulo -->
            <version>0.0.1</version>

        </Poesia_HolaMundo>
    </modules>

    <frontend>
      <!-- Lo que necesitamos para utilizar los controladores -->
      <routers>
    <holaMundo>
      <use>standard</use>
      <args>
        <module>Poesia_HolaMundo</module>
        <frontName>hm</frontName>
      </args>
    </holaMundo>
      </routers>
      <!-- Lo que necesitamos para utilizar los controladores -->
      <!-- Lo que necesitamos para el layout y las plantillas -->
      <layout>
    <updates>
      <holamundo>
        <file>poesia.xml</file>
      </holamundo>
    </updates>
      </layout>
      <!-- Lo que necesitamos para el layout y las plantillas -->
    </frontend>
    <!-- Necesario para informar a Magento sobre nuestro modelo -->
    <global>
      <models>
    <holamundo>
        <class>Poesia_Holamundo_Model</class>
        <resourceModel>holamundo_resource</resourceModel>
    </holamundo>
    <holamundo_resource>
        <class>Poesia_HolaMundo_Model_Resource</class>
        <entities>
        <pventamod>
            <table>poesia_postvtable</table>
        </pventamod>
        </entities>
    </holamundo_resource>
      </models>
      <resources>
        <holamundo_setup>
          <setup>
            <module>Poesia_HolaMundo</module>
          </setup>
          <connection>
            <use>core_setup</use>
          </connection>
        </holamundo_setup>
        <holamundo_write>
          <connection>
            <use>core_write</use>
          </connection>
        </holamundo_write>
        <holamundo_read>
          <connection>
            <use>core_read</use>
          </connection>
        </holamundo_read>
      </resources>

    </global>
    <!-- Necesario para informar a Magento sobre nuestro modelo -->
</config>

Ahora creamos el modelo (le intento dar a todo nombres diferentes para que veamos qué es cada cosa). Más o menos esto son algunas definiciones básicas para empezar a trabajar.
[modelo y todo eso luego]

Creamos la tabla en la base de datos

Aunque se puede hacer todo directamente, yo prefiero crear la tabla a mano primero para ir haciendo pruebas y asegurarme de que todo va funcionando bien. Más adelante crearemos un script que se encargará de generar la tabla, pero, por ahora la crearemos a mano en MySQL para asegurarnos de que todo encaja. Supondremos que el prefijo de las tablas de Magento es “mage_”, que viene por defecto, lo podemos ver en app/etc/local.xml (config.global.resources.db.table_prefix). Lo siguiente, lo ejecutaremos directamente en nuestro servidor de base de datos, ya sea por consola, o a través de PHPMyAdmin o similares.

1
2
3
4
5
6
7
CREATE TABLE mage_poesia_postvtable (
   table_id BIGINT NOT NULL AUTO_INCREMENT,
   user_id BIGINT,
   user_email VARCHAR(192),
   comment TEXT,
   PRIMARY KEY(table_id)
) ENGINE=InnoDB DEFAULT CHARSET='UTF8';

Como en el XML dijimos que el nombre de la tabla era poesia_postvtable, le ponemos el prefijo delante al crearla.

Y como estamos probando y sólo queremos algunos datos sin sentido para saber que todo va bien:

1
2
3
INSERT INTO mage_poesia_postvtable VALUES (NULL, 1, 'usuario1@servidor.ext', 'Never forget the WHERE');
INSERT INTO mage_poesia_postvtable VALUES (NULL, 100, 'user2@server.ext', 'What does the fox say?');
INSERT INTO mage_poesia_postvtable VALUES (NULL, 123, 'usuario3@server.ext', 'The day the routers die');

Crear estructura de ficheros del modelo

Ahora toca el turno de crear ficheros y directorios. Para ello, vamos a crear dentro del directorio de nuestro plugin el siguiente árbol de directorios (en mi caso app/code/local/Poesia/HolaMundo/):

  • Model (aquí irán todos los modelos)
    • Resource (dentro de los modelos tendremos los recursos)
      • Pventamod (será el correspondiente al modelo que vamos a hacer)

Ahora crearemos los archivos necesarios para utilizarlos:
app/code/local/Poesia/HolaMundo/Model/Pventamod.php

1
2
3
4
5
6
7
8
9
<?php

class Poesia_HolaMundo_Model_Pventamod extends Mage_Core_Model_Abstract
{
  public function _construct()
  {
    parent::_construct();
    $this->_init('holamundo/pventamod');
  }

app/code/local/Poesia/HolaMundo/Model/Resource/Pventamod.php

1
2
3
4
5
6
7
8
<?php
class Poesia_HolaMundo_Model_Resource_Pventamod extends Mage_Core_Model_Resource_Db_Abstract
{
  protected function _construct()
  {
    $this->_init('holamundo/pventamod', 'table_id');
  }
}

app/code/local/Poesia/HolaMundo/Model/Resource/Pventamod/Collection.php

1
2
3
4
5
6
7
8
9
10
<?php

class Poesia_HolaMundo_Model_Resource_Pventamod_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract
{
  public function _construct()
  {
    parent::_construct();
    $this->_init('holamundo/pventamod');
  }
}

¡¡Ya está listo nuestro modelo!!

Haciendo algo con el modelo

Ya podemos empezar a trabajar con nuestro modelo (no vamos a entrar en detalle en la utilización del ORM de Magento), por ejemplo, consultando información. Para ello, vamos a utilizar una vista (podemos utilizar una vista de nuestro controlador (holamundo), y hacer lo siguiente:
app/design/frontend/base/default/template/holamundo/test.phtml

1
2
3
4
5
6
7
8
9
10
<p>Ejemplo de vista de TEST</p>
<?php
    $model = Mage::getmodel('holamundo/pventamod');
    $primero = $model->load(1);
    echo get_class($primero);
    echo "ID: ". $primero->getTableId()."<br/>";
    echo "Userid: ".$primero->getUserId()."<br/>";
    echo "Email: ".$primero->getUserEmail()."<br/>";
    echo "Comentario: ".$primero->getComment()."<br/>";
?>

Auto-creación de tablas

Para facilitar al usuario a la hora de instalar plugins, facilitar las actualizaciones cuando las pasamos a producción y agilizar todo el proceso. Consiste en una serie de scripts para crear y actualizar la base de datos, que nos permitirá ejecutar cualquier sentencia SQL ante la presentación de una determinada versión de nuestro plugin.

Vamos a crear, dentro del directorio de nuestro plugin, el directorio sql, y dentro de éste holamundo_setup (igual que estaba puesto bajo resources en nuestro config.xml). Dentro crearemos un archivo llamado install-0.0.1.php (0.0.1 es la versión de nuestro plugin, que la pusimos cuando creamos el config.xml).

Nuestro archivo app/code/local/Poesia/HolaMundo/sql/holamundo_setup/install-0.0.1.php será el siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

$installer = $this;

$installer->startSetup();

$installer->run("

CREATE TABLE IF NOT EXISTS `{$this->getTable('poesia_postvtable')}`(
   table_id bigint NOT NULL AUTO_INCREMENT,
   user_id BIGINT,
   user_email VARCHAR(192),
   comment TEXT,
   PRIMARY KEY(table_id)
) ENGINE=InnoDB DEFAULT CHARSET='utf8';
    "
);

$installer->run("INSERT INTO `{$this->getTable('poesia_postvtable')}`
   VALUES (NULL, 10, 'email@email.com', 'comentario de prueba')"
);

$installer->endSetup();

Podemos ver que para colocar el nombre de la tabla utilizamos $this->getTable(), esta función incluirá el nombre de la tabla con el prefijo del sistema. No es obligatorio poner un INSERT, yo lo he puesto para que el ejemplo funcione directamente.

Para comprobar que este script se ejecuta, sólo en pruebas, podemos introducir un die(‘Me ejecuto’) al principio del archivo de instalación. Así veremos que todo marcha bien.

Si vemos que, aunque borrando la base de datos, no se carga el script de instalación, podemos forzarlo haciendo que el sistema olvide nuestro plugin, accediendo a la base de datos y buscando la tabla “mage_core_resource” (de nuevo supongo que vuestro prefijo es mage_), ahí podemos hacer lo siguiente:

mysql [localhost] (magento) > SELECT * FROM mage_core_resource WHERE code LIKE ‘%holamundo%’;
+—————–+———+————–+
| code | version | data_version |
+—————–+———+————–+
| holamundo_setup | 0.0.1 | 0.0.1 |
+—————–+———+————–+
1 row in set (0.00 sec)

mysql [localhost] (magento) > DELETE FROM mage_core_resource WHERE code LIKE ‘%holamundo%’;
Query OK, 1 row affected (0.00 sec)

Tened cuidado por si borráis algo necesario, aquí sólo estamos borrando nuestro plugin, pero si hay algún plugin más, debemos utilizar su nombre completo.

Ahora cuando recarguemos alguna página de Magento, el plugin se instalará y de nuevo podremos ver la tabla en nuestra base de datos (y empezar a operar con ella). Si de hecho es la primera vez que esto se ejecuta en esta instalación de Magento, esto será transparente para el usuario.

Actualizando plugins en la base de datos

Cuando actualizamos un plugin que hemos creado, es común cambiar cosas en las tablas, imaginemos que hemos metido un campo más en la tabla, variado longitudes de campo, añadido claves, etc. Para eso tenemos los scripts de actualización. De la misma forma que los scripts de instalación, éstos estarán situados en app/code/local/NombreEmpresa/NombrePlugin/sql/recurso_setup/ y tendrán como nombre “upgrade-[versión.antigua]-[versión_nueva].php.

Ahora, nuestro plugin lo actualizamos a la versión 0.2.0 (antiguamente tenía la 0.0.1) entonces crearemos un script llamado:
app/code/local/Poesia/HolaMundo/sql/holamundo_setup/upgrade-0.0.1-0.2.0.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

$installer = $this;

$installer->startSetup();

$installer->run("

ALTER TABLE `{$this->getTable('poesia_postvtable')}`
   ADD COLUMN tipo BIGINT NOT NULL;"
);

$installer->endSetup();

y con esto añadimos la columna tipo que podremos utilizar a partir de este instante.

Foto: Susana Fernandez (Flickr CC-By)

The post Creando un modelo sencillo en Magento (paso a paso y con ejemplos) appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Variable not found

Precompilación de vistas en MVC 6, powered by Roslyn

April 21, 2015 07:05 AM

ASP.NET MVCSeguro que ya todos conocéis la fórmula mágica mediante la cual podemos activar la compilación de vistas en versiones de ASP.NET MVC anteriores a la 6. Los que no sepáis de qué os hablo, podéis echar un vistazo a este vídeo que publiqué en el blog de CampusMVP hace algún tiempo: VIDEO: Activar la compilación de vistas en ASP.NET MVC.

MvcBuildViewsMuy resumidamente, el asunto consistía en editar manualmente el archivo de proyecto de Visual Studio, con extensión .csproj, y establecer el contenido del tag <MvcBuildViews> a true.


A partir de ese momento, y tras recargar el proyecto, Visual Studio comienza a compilar las vistas como parte del proceso de construcción de la solución. Obviamente este proceso tardará un poquito más, pero al menos de esta forma tenemos la seguridad de que las vistas no van a explotar en tiempo de ejecución por errores de compilación.

Por otra parte, sabemos que el nuevo ASP.NET 5 viene con bastantes novedades, entre las que destaca la desaparición y de muchos archivos clásicos, como el web.config, el global.asax… y también el .csproj. Y dado que era en éste donde activábamos la compilación de vistas, ¿dónde ha ido a parar ahora esa característica?

Pero antes de continuar, el tradicional disclaimer: en estos momentos ASP.NET 5 y MVC 6 se encuentran en fase de desarrollo, y todo lo que digamos a partir de ahora puede quedar en agua de borrajas.

Bien, pues la respuesta a la pregunta anterior la encontramos en Roslyn. Creo que todavía nos falta mucho hasta llegar a comprender el potencial y las posibilidades que se abren tras la llegada de este nuevo compilador, pero que lo que vamos a ver ahora es seguro un buen ejemplo.

image
Resulta que con Roslyn es posible introducir código personalizado en el momento de la compilación, y MVC aprovecha esta característica para insertar la compilación de las vistas Razor en el proceso.

Si observamos un proyecto ASP.NET 5 generado usando la plantilla  de Visual Studio 2015, podemos ver que existe un archivo RazorPreCompilation.cs en la carpeta /Compiler/Preprocess, como se muestra en la captura de pantalla adjunta.

En su interior, encontramos una clase llamada RazorPreCompilation, que hereda de la clase suministrada por MVC RazorPreCompileModule, que a su vez implementa el interfaz ICompileModule proporcionado por Roslyn. El código que trae esta clase por defecto es el siguiente:

RazorPreCompilation

Durante la compilación, Roslyn busca en esa carpeta exacta módulos de preproceso, que en la práctica son archivos con clases que implementan ICompileModule, y les cede el control antes y después de compilar, dándoles la oportunidad de introducir entradas al árbol sintáctico resultante de la compilación o mensajes de diagnóstico y error al resultado.

La clase que añadimos a nuestra aplicación en esa carpeta puede tener cualquier nombre, pero lo importante es que herede de RazorPreCompilation (definido en Microsoft.AspNet.Mvc ), pues se trata de la implementación de ICompileModule que utiliza internamente el precompilador de vistas de Razor para generar los resultados.

Resumiendo, lo único que necesitamos para que las vistas de nuestra aplicación se precompilen es crear una clase cualquiera que herede de RazorPreCompileModule en la carpeta /Compiler/Preprocess del proyecto, y Roslyn se encargará del resto :)

Publicado en Variable not found.

» Leer más, comentarios, etc...

proyectos Ágiles

Agile en la revista Emprendedores

April 20, 2015 09:23 PM

La divulgación de Agile y Lean sigue llegando al gran público !!

Este mes, la revista Emprendedores incluye el Dossier "Haz tu negocio más eficiente", donde se comenta la necesidad de la Agilidad en la respuesta al mercado y se identifican los desperdicios en el trabajo desde una perspectiva Lean.

 revista-emprendedores-haz-tu-negocio-mas-eficiente

 

Artículos relacionados

» Leer más, comentarios, etc...

Arragonán

Semana 358

April 20, 2015 12:45 PM

Hoy llevo síndrome post Startup Open Space. Que estoy bastante machacado aún, vamos. La verdad que creo que salió todo bastante bien, y este año lo disfruté incluso más que en la edición anterior, se notó que a nivel organizativo lo llevábamos mucho más rodado.

Cachirulo Crew

Cachirulo Crew. De izquierda a derecha: @danieltwal @torhector2 @lauralacarra @pablojimeno @dani_latorre @gimenete @aaromnido. Ausentes en la foto: @rrasmo @superwillyfoc @olmeras. Foto de @capitangolo.

A nivel de contenido, me gustaron bastante las sesiones a la que asistí, con el nivel que había entre los asistentes se podía presuponer que la cosa no saliera mal. También, como de costumbre, me lo pasé genial con las charlas entre las cervezas de ambas noches y ejerciendo un poco de guía turístico para los foranos :P. En fin, ayer viendo el hashtag en twitter parece que la cosa gustó bastante, ahora nos queda recoger algo de feedback para ver cómo podemos mejorar para la siguiente.

Y aunque el sosZ15 ocupara gran parte de mi semana, también hice más cosas. Por ejemplo: estuve grabando con los amigos del videoblog Qué pasa Co!, que han empezado a hacer entrevistas y estuve ahí para hablar de Mosica.

Continuamos una semana más con SenpaiDevs, seguimos trabajando en el proyecto del calendario y parece que pronto podremos dar por acabada la primera versión. Esta semana ya he empezado a notar que se está haciendo un grupete majo al haber poco a poco más confianza entre todos; además parece que empieza a picar el gusanillo de participar en las comunidades locales (uno de nuestros objetivos con esto).

Cerrando la semana tuvimos una reunión con una empresa aragonesa para ver si podíamos colaborar para echarles una mano en temas de testing, que están empezando con ello y sienten que necesitarán ayuda.

En proyectos actuales:

  • Ya tengo casi lista la app móvil de Mosica. Mientras en la web hice alguna pequeña modificación a nivel de API y modifiqué el mapa de la página de un concierto a los basemaps de cartodb.
  • Continué trabajando en One-stop, exponiendo un API para ofrecer un método de importación de datos automatizada y seguir desarrollando algunas funcionalidades en el backoffice.
  • Aunque retomé mi trabajo con Bichomanía, apenas pude adelantar, esta semana tocará ponerse las pilas.

Buena semana.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 195

April 20, 2015 07:15 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada, espero que os resulten interesantes :-)

.Net

ASP.NET

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

» Leer más, comentarios, etc...

Koalite

Recopilatorio sobre modelos de dominio

April 20, 2015 05:06 AM

Un problema de muchos blogs, y en especial de éste, es que el contenido se va generando según le apetece al autor, o sea a mi, y eso hace que a veces la organización no sea todo lo buena que a uno le gustaría, especialmente si no eres un lector frecuente y caes por aquí de casualidad. Para intentar paliar ese problema, he decidido escribir este post para recopilar lo que he escrito sobre cómo diseñar modelos de dominio y así poder encontrar ese material más fácilmente.

Conceptos básicos

En el post sobre diseño de modelos veíamos distintos tipos de modelos y hablábamos sobre la evolución desde modelos relacionales a modelos orientados a objetos pasando por modelos anémicos. Merece la pena echarle un vistazo, aunque sólo sea por leer los distintos puntos de vista que se exponen en los comentarios.

Aunque no es un requisito indispensable, muchas veces se asocia tener un modelo de dominio con aplicar DDD como proceso. En ese sentido, deberías plantearte si puedes hacer DDD sin un experto de dominio. Nuevamente la discusión de los comentarios es más interesante que el post.

Cómo construir un modelo de dominio

Para diseñar un modelo de dominio, es necesario identificar los aggregate roots alrededor de los cuales construiremos el modelo, y buscar formas de enriquecerlo con comportamiento para huir de un modelo anémico.

En ese sentido, podemos quitar lógica de servicios para pasarla a entidades y value objects o darle más peso a nuestros value objects evitando usar tipos enumerados.

También podemos utilizar eventos de dominio para desacoplar el modelo de sistemas externos, aunque eso sí, debemos tener cuidado de cómo gestionamos las transacciones al usar eventos de dominio.

Conceptos sobre orientación a objetos

Al final, el modelo de dominio no deja de ser un diseño orientado a objetos (al menos en estos posts), por lo que los principios básicos de diseño orientado a objetos se aplican al modelo.

Por ello viene bien comprender lo que son la cohesión y el acoplamiento, cómo aplicar la Ley de Demeter, el principio de Tell, Don’t Ask (y los riesgos asociados) o qué significa realmente la inversión de dependencias. Tampoco está de más que cuando empieces a dejarte llevar por la fiebre polimórfica orientada a objetos, seas consciente de que no siempre se puede abstraer todo, y que si algo no lo puedes abstraer, mejor hazlo explícito.

Podemos conseguir un modelo más sólido si aprovechamos técnicas como el diseño por contrato, especialmente para tener claros los invariantes que debemos mantener dentro de cada clase que forma parte del modelo. Esto puede influir en el tipo de colecciones que usamos en cada momento. A veces el tema de los invariantes, precondiciones y demás se confunde con las necesidades de securizar, autorizar y validar.

Persistencia

Por supuesto he escrito mi buena cuota de posts sobre persistencia (¿por qué nos gustará tanto darle vueltas a lo mismo?).

Puedes empezar por ver las diferencias entre un ORM, un Micro-ORM y ADO.NET y ver cuándo usar cada uno. Si te quedan dudas, en este post explico por qué sigo usando un ORM, aunque sea algo que empieza a estar pasado de moda en ciertos círculos.

Cuando utilizas un modelo de dominio, el patrón de diseño por excelencia para gestionar la persistencia es el repositorio, en cualquiera de sus variantes: el repositorio genérico, el repositorio concreto, el repositorio implícito (usar directamente el ORM) o la separación de lecturas y escrituras. La tendencia actual es cada vez más no utilizar repositorios y usar directamente el ORM, pero los repositorios como abstracción también aportan un valor que puede ser interesante.

Una nota final

Es posible que me deje algún post que pudiera tener cabida en este resumen (si me avisas en los comentarios, lo añado), pero creo que esta “selección” incluye los posts que más te pueden servir para diseñar un bueno modelo de dominio.

No tengo por costumbre reescribir posts antiguos, y esta vez tampoco lo he hecho, por lo que es posible que si lees varios de los posts citados notes algunas inconsistencias o, directamente, contradicciones. Es normal. Todo evoluciona con el tiempo y la forma de ver las cosas cambia con la experiencia. Tómatelo como un consejo más: lo que hoy piensas que es la mejor opción, mañana puede dejar de parecértelo.

Posts relacionados:

  1. Desacoplar modelos con Eventos de Dominio
  2. Crear modelos más ricos quitando lógica de los servicios
  3. Eventos de Dominio y Transacciones

» Leer más, comentarios, etc...

Navegapolis

Fórmula para reducir el coste laboral de los programadores

April 17, 2015 07:06 AM

coste laboralEl coste laboral está en relación directa con el salario: coste = salario, pero con un modificador importante: "valor que aporta la persona".

coste = salario / valor.

En la manufactura industrial, y demás trabajos que aplican ingeniería de procesos para garantizar la calidad del resultado,  y que la diferencia entre las personas no resulte significativa, al factor "valor" se le puede considerar una constante.
Además la ingeniería de procesos minimiza la pérdida de know how en la rotación de personal, así que si no escasean los "operarios" en el mercado laboral, se puede simplificar la fórmula y dejarla en "coste = salario", considerando más barato al que menos cobra.

Sin embargo, en la construcción de software, la diferencia de valor aportado entre los buenos y los mejores es enorme. Tan grande que resulta miope mirar al factor "salario" para reducir el coste.
Y por supuesto a los malos y mediocres, ni los considere. A ningún precio; porque disparan el coste al no aportar valor, o aportarlo negativo, porque degradan y complican el código tocan.

 

» Leer más, comentarios, etc...

Juanjo Navarro

Cursos de Google en Udacity

April 16, 2015 03:34 PM

Google anunció la semana pasada un curso sobre rendimiento en Android en la plataforma de enseñanza online Udacity.

Udacity y Google

El curso se estructura en cuatro bloques, que trata problemas de rendimiento respectivamente en renderizado, proceso, memoria y batería.

Este curso se une además a los varios que Google tiene en la plataforma Udacity (y que se pueden consultar desde el catálogo de cursos, filtrando por el listado de la izquierda). Los cursos van desde temas genéricos de diseño responsive hasta tecnologías propias de Google como este de Android (hay varios más sobre Android) o el App Engine (tienen cursos de Python y Java en el App Engine).

» Leer más, comentarios, etc...

Picando Código

Workshop Girls Make Games en Montevideo

April 15, 2015 03:00 PM

El fin de semana del 25 y 26 de Abril se organiza en Montevideo el workshop Girls Make Games, diseñado para inspirar a la próxima generación de diseñadoras, creadoras e ingenieras:

Girls Make Games Montevideo 2015

En “por qué importa”, el sitio de GMG explica que si bien el 47% de videojugadores son mujeres, las mujeres representan menos del 12% de la industria de los videojuegos. Es una industria que se prevee alcance 90 mil millones de dólares de ingresos en 2017.

Como dice la imagen, la inscripción es gratuita y el taller va a ser en Sinergia Cowork, Gonzalo Ramírez 1676.

» Leer más, comentarios, etc...

Blog Bitix

Guardar contraseñas usando «Salted Password Hashing» y otras formas correctas

April 14, 2015 07:00 PM

Apache Shiro

Para cada servicio deberíamos emplear una contraseña de una longitud de al menos 8 caracteres que incluya letras en minúscula, mayúscula, números y símbolos, una herramienta que podemos utilizar para generar contraseñas más seguras con los criterios que indiquemos es Strong Password Generator. Sin embargo, recordar cada una de estas contraseñas es muy difícil de modo que es habitual que utilicemos la misma contraseña para varios o todos los servicios y no empleando todos los criterios anteriores. Por otro lado, los desarrolladores no deberíamos guardar en la base de datos las contraseñas que nos entregan los usuarios en texto plano, para evitar guardalas en texto plano hace un tiempo se utilizaba únicamente una función de hashing unidireccional como MD5 o SHA, de este modo si la base de datos fuese comprometida en teoría no podrían conocer la contraseña original. En este artículo comentaré que aún guardando las contraseñas con una función de hashing no es suficiente para hacerlas seguras y comentaré una implementación con Apache Shiro de una de las ideas propuestas.

Algo de teoría y algunas explicaciones

Java

Aunque guardemos las contraseñas con MD5 o alguna variante de SHA hoy en día no es suficiente para que en caso de que alguien obtenga los hashes de las contraseñas de la base de datos pueda averiguarlas o dar con una que genere el mismo hash, usando estas funciones se pueden encontrar colisiones en un tiempo razonable y por tanto ya no se consideran seguras. Dada la computación actual de los procesadores y las tarjetas gráficas una contraseña débil puede romperse usando un ataque de fuerza bruta y quizá antes con un ataque de diccionario que pruebe las más comunes. Muchos usuarios no tienen contraseñas largas ni utilizan letras en minúscula, mayúscula, números y símbolos, muchos usuarios utilizan contraseñas sencillas para ser recordadas más fácilmente, y aún hasheando las contraseñas pueden ser averiguadas. También se pueden usar tablas arcoiris o rainbow tables con los hashes precalculados de las contraseñas de un diccionario con lo que el tiempo empleado para romper una puede requerir poco tiempo de computación.

También hay que tener en cuenta que muchos usuarios usan la misma contraseña para múltiples servicios por lo que basta que alguien obtenga la contraseña original de un servicio y podrá acceder a otros más interesantes para alguien con malas intenciones por mucha seguridad que tenga esos otros servicios, este es uno de los motivos de la autenticación en dos pasos (que emplea algo que sé, la contraseña, y algo que tengo, como el móvil) y la recomendación de usar una contraseña diferente para cada servicio. Las contraseñas por si solas tiene la seguridad más baja de los diferentes servicios donde se usen.

Con Salted Password Hashing el uso de rainbow tables que aceleren el ataque no serían posibles por la entropía añadida por los salt. Aún así conociendo el salt y la función de hash empleada seguiría siendo posible un ataque de fuerza bruta y de diccionario. Con Salted Password Hashing se usa en la función de hash y un dato variable denominado salt que añade suficiente entropía y es diferente para cada contraseña, en la base de datos se guarda el resultado de la función de hash junto con el salt, esto es, el resultado de SHA-512(contraseña+salt) y también el salt.

Ejemplo de Salted Password Hashing usando Apache Shiro

Antes de comentar alguna opción más que dificulte los ataques de fuerza bruta o de diccionario veamos como implementar Salted Password Hashing empleando Apache Shiro como librería de autenticación y autorización para los usuarios. El ejemplo será simple sin guardar los datos en una base de datos pero suficiente para mostrar que se debe añadir al proyecto para que Shiro compruebe las contraseñas usando una función de hash y un salt. Partiré de un ejemplo que hice para el libro PlugIn Tapestry sobre el desarrollo de aplicaciones web con el framework Apache Tapestry. Básicamente deberemos crear un nuevo Realm que devuelva los datos del usuario, el hash y el salt. Una implementación suficiente para el ejemplo sería la siguiente, la parte importante está en el método doGetAuthenticationInfo y en la inicialización static de la clase:

<noscript><pre><code>package es.com.blogspot.elblogdepicodev.plugintapestry.misc; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.shiro.authc.AccountException; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.ExpiredCredentialsException; import org.apache.shiro.authc.LockedAccountException; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.cache.MemoryConstrainedCacheManager; import org.apache.shiro.crypto.SecureRandomNumberGenerator; import org.apache.shiro.crypto.hash.Sha512Hash; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.util.ByteSource; import org.apache.shiro.util.SimpleByteSource; public class Realm extends AuthorizingRealm { private static Map&lt;String, Map&lt;String, Object&gt;&gt; users; private static Map&lt;String, Set&lt;String&gt;&gt; permissions; // Para hacer más costoso el cálculo del hash y dificultar un ataque de fuerza bruta private static final int HASH_ITERATIONS = 5_000_000; static { // Generar una contraseña de clave «password», con SHA-512 y con «salt» aleatorio. ByteSource saltSource = new SecureRandomNumberGenerator().nextBytes(); byte[] salt = saltSource.getBytes(); Sha512Hash hash= new Sha512Hash(&quot;password&quot;, saltSource, HASH_ITERATIONS); String password = hash.toHex(); // Contraseña codificada en Base64 //String password = hash.toBase64(); // Permissions (role, permissions) permissions = new HashMap&lt;&gt;(); permissions.put(&quot;root&quot;, new HashSet&lt;&gt;(Arrays.asList(new String[] { &quot;cuenta:reset&quot; }))); // Roles Set&lt;String&gt; roles = new HashSet&lt;&gt;(); roles.add(&quot;root&quot;); // Usuario (property, value) Map&lt;String, Object&gt; user = new HashMap&lt;&gt;(); user.put(&quot;username&quot;, &quot;root&quot;); user.put(&quot;password&quot;, password); user.put(&quot;salt&quot;, salt); user.put(&quot;locked&quot;, Boolean.FALSE); user.put(&quot;expired&quot;, Boolean.FALSE); user.put(&quot;roles&quot;, roles); // Usuarios users = new HashMap&lt;&gt;(); users.put(&quot;root&quot;, user); } public Realm() { super(new MemoryConstrainedCacheManager()); HashedCredentialsMatcher cm = new HashedCredentialsMatcher(Sha512Hash.ALGORITHM_NAME); cm.setHashIterations(HASH_ITERATIONS); //cm.setStoredCredentialsHexEncoded(false); setName(&quot;local&quot;); setAuthenticationTokenClass(UsernamePasswordToken.class); setCredentialsMatcher(cm); } /** * Proporciona la autenticación de los usuarios. */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken atoken = (UsernamePasswordToken) token; String username = atoken.getUsername(); if (username == null) { throw new AccountException(&quot;Null usernames are not allowed by this realm.&quot;); } Map&lt;String, Object&gt; user = findByUsername(username); String password = (String) user.get(&quot;password&quot;); byte[] salt = (byte []) user.get(&quot;salt&quot;); boolean locked = (boolean) user.get(&quot;locked&quot;); boolean expired = (boolean) user.get(&quot;expired&quot;); if (locked) { throw new LockedAccountException(&quot;Account [&quot; + username + &quot;] is locked.&quot;); } if (expired) { throw new ExpiredCredentialsException(&quot;The credentials for account [&quot; + username + &quot;] are expired&quot;); } return new SimpleAuthenticationInfo(username, password, new SimpleByteSource(salt), getName()); } /** * Proporciona la autorización de los usuarios. */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { if (principals == null) throw new AuthorizationException(&quot;PrincipalCollection was null, which should not happen&quot;); if (principals.isEmpty()) return null; if (principals.fromRealm(getName()).size() &lt;= 0) return null; // Obtener el usuario String username = (String) principals.fromRealm(getName()).iterator().next(); if (username == null) return null; Map&lt;String, Object&gt; user = findByUsername(username); if (user == null) return null; // Obtener los roles Set&lt;String&gt; roles = (Set&lt;String&gt;) user.get(&quot;roles&quot;); // Obtener los permisos de los roles Set&lt;String&gt; p = new HashSet&lt;&gt;(); for (String role : roles) { p.addAll((Set&lt;String&gt;) permissions.get(role)); } // Devolver el objeto de autorización SimpleAuthorizationInfo ai = new SimpleAuthorizationInfo(); ai.setRoles(roles); ai.setStringPermissions(p); return ai; } private Map&lt;String, Object&gt; findByUsername(String username) { return users.get(username); } }</code></pre></noscript>

Las contraseñas hasheadas tendrán la siguiente forma, podemos guardarlas codificadas en formato hexadecimal o en formato Base64:

<noscript><pre><code>Hex: 53a8b4b7eb9f5b8a0754916bcf2e11443149e8d0eb933624abf6feec4a8f43799bc177e0817a2a9df204d7c3597a379689f466f9b3bfe14b534c8d824ceeee22 Base64: U6i0t+ufW4oHVJFrzy4RRDFJ6NDrkzYkq/b+7EqPQ3mbwXfggXoqnfIE18NZejeWifRm+bO/4UtTTI2CTO7uIg==</code></pre></noscript>

En el ejemplo tratándose de una aplicación web usando Apache Tapestry se debe modificar la configuración para que se utilice el nuevo Realm el antiguo guardaba las contraseñas en texto plano (shiro-users.properties).

<noscript><pre><code>... public static void contributeWebSecurityManager(Configuration&lt;Realm&gt; configuration) { // Realm básico // ExtendedPropertiesRealm realm = new ExtendedPropertiesRealm(&quot;classpath:shiro-users.properties&quot;); // Realm con «salted password hashing» y «salt» Realm realm = new es.com.blogspot.elblogdepicodev.plugintapestry.misc.Realm(); configuration.add(realm); } ...</code></pre></noscript>

El cambio de Realm para el usuario no supone ninguna modificación y podrá seguir autenticandose con con su misma contraseña. En el ejemplo con root como usuario y password como contraseña.

Este es todo el código que necesitamos para la implementación de contraseñas codificadas con una función de hashing, en este caso SHA-512, y un salt, no es mucho y además es bastante simple la implementación con Shiro y en este caso en una aplicación usando el framework Apache Tapestry. Estas pocas líneas de código pueden aumentar notablemente la seguridad de las contraseñas que guardamos en la base de datos. En el caso de que la base de datos se vea comprometida será más difícil para alguien con malas intenciones obtener las contraseñas originales.

El siguiente ejemplo de federatedaccounts puede verse como usar está técnica de hash con salt usando una base de datos. Básicamente es lo mismo pero accediendo a base de datos para obtener el hash de la contraseña y el salt con una entidad JPA.

Otras opciones que añaden más seguridad

Aún así como comento este ejemplo de Salted Password Hashing aunque dificulta un ataque aún es viable usar fuerza bruta o un diccionario. En el artículo Password Security Right Way comentan tres ideas más. Una es usar como función de hash Bcrypt no porque sea más segura que SHA-512 sino porque es más lenta y esto puede hacer inviable la fuerza bruta o de diccionario, hay planes de proporcionar Bcrypt en Apache Shiro en futuras versiones. En el ejemplo como alternativa a bcrypt se usan varios millones de iteraciones de aplicación de la función para añadir tiempo de cálculo al hash, este tiempo adicional no es significativo en el cálculo de un hash pero en un ataque de fuerza bruta puede aumentarlo de forma tan significativa que sea inviable. La segunda idea interesante es además de hashear la clave es cifrarla de modo que aún habiendo sido comprometida la base de datos se necesite la clave privada de cifrado que también debería ser comprometida para producir el ataque. La tercera es partir el hash y distribuirlo entre varios sistemas de modo que sea necesario romperlos todos para obtener en hash original, lo que dificulta aún más un ataque.

Para implementar la segunda opción deberemos proporcionar implementaciones propias de CredentialsMatcher y de SimpleHash, quizá esto sea tema para otro artículo.

Código fuente del ejemplo

El código fuente completo del ejemplo está alojado en un repositorio de GitHub, es completamente funcional y puedes probarlo en tu equipo. Una vez descargado el siguiente comando e introduciendo en el navegador http://localhost:8080/PlugInTapestry, en la página que se muestra hay un botón para iniciar sesión:

<noscript><pre><code>$ ./gradlew tomcatRun</code></pre></noscript>

Nota final

En este artículo recomiendo leer los interesantes enlaces del apartado de referencia del final, de ellos los siguientes dos son bastante completos Password Security the Right Way y The RIGHT Way: How to Hash Properly aunque todos merecen el tiempo dedicado a una lectura detenida. Para terminar mucho de esto es fútil si se permiten contraseñas sencillas por lo que exigir contraseñas con cierta fortaleza de la forma comentada al principio también es necesario si la seguridad de la aplicación es un requisito importante.

Referencia:
Password Security the Right Way
How To Safely Store A Password
Password Security with Stormpath
Strong Password Hashing With Apache Shiro
The RIGHT Way: How to Hash Properly
Apache Shiro, Hashing and Corresponding Matchers
Apache Shiro, Hashing Credentials
http://tynamo.org/tapestry-security+guide
Strong Password Generator
Encriptar y guardar contraseñas en base de datos
Seguridad en el almacenamiento de Passwords/Contraseñas
Usuarios con contraseñas repetidas: ciberdelincuentes felices
Un HASH MD5 en la password no sustituye a SSL
Ataque de fuerza bruta
Ataque de diccionario
Tablas arcoiris o rainbow tables

» Leer más, comentarios, etc...

Variable not found

101 citas célebres más del mundo de la informática (¡505 ya!)

April 14, 2015 10:07 AM

PensandoSin duda, posts pertenecientes a la serie recopilatoria de citas célebres relacionadas con el mundo de la informática (primero, segundo, tercero y cuarto) siguen siendo, año tras año, los contenidos más populares de este blog, probablemente por la mezcla de conocimiento, humor, ingenio y realidad sobre nuestro día a día que incluyen estos mensajes.

Tras su última entrega, allá por septiembre de 2012, he continuado recopilando todas las citas que han caído en mis manos y me han resultado curiosas, hasta llegar por fin a las 101 que os traigo hoy. Espero que os iluminen de nuevo o, al menos, que os hagan pasar un rato tan bueno como los que paso yo mientras las voy seleccionando :)

Actitudes

  1. “No tengo talentos especiales. Sólo soy apasionadamente curioso”
    -- Albert Einstein
              
  2. “No permitas que lo que no puedes hacer interfiera con lo que puedes hacer"
    -- John Wooden
     
  3. “Dándole la vuelta a Descartes: Existes. Así que piensa"
    -- Seth Godin
             
  4. “Si deseas tener éxito, tienes que duplicar tu tasa de fracasos”
    -- Tom Watson Jr, presidente de IBM
     
  5. “Si no puedes explicarlo de forma simple es que no lo entiendes lo suficientemente bien“ 
    -- Albert Einstein  
  6. “Lo imposible es muy a menudo lo que no se ha probado”
    -- Jim Goodwin
              
  7. “El pesimista se queja por el viento; el optimista espera que cambie; el realista ajusta las velas”
    -- William Arthur Ward
      
  8. No os necesitamos, ni si quiera habéis terminado la universidad
    -- HP, a Jobs y Wozniak
     
  9. “Errar es humano; reconocer es palíndromo”
    -- Nicolás M. Pousen 

Aptitudes

  1. “Cuando alguien te pregunte si puedes hacer un trabajo, dile ‘por supuesto que sí’. Y ponte inmediatamente a aprender cómo hacerlo”
    -- Theodore Roosevelt
     
  2. “¿Qué pasa si formo a mi gente y se me va? Mejor pregúntate qué pasa si no los formas y se quedan”
    -- Javier Eslava
     
  3. “Cuidado con el falso conocimiento; es más peligroso que la ignorancia”
    -- George Bernard Shaw
     
  4. “Vacía tus bolsillos para llenar tu cerebro, y tu cerebro llenará tus bolsillos”
    -- Benjamin Franklin
     
  5. “Si piensas que es caro contratar un profesional, espera a contratar un amateur”
    -- Autor desconocido
     
  6. Desarrolla pasión por el aprendizaje; si lo haces, nunca dejarás de crecer”
    -- Anthony J. D'Angelo
     
  7. En quince años estaremos enseñando programación de la misma forma que hacemos con la lectura o escritura… y me pregunto por qué no lo hemos hecho antes”
    -- Mark Zuckerberg

Programación

  1. “Cualquier método que evite al programador escribir código es un buen método”
    -- Trygve M. H. Reenskaug
     
  2. “¡Escribí la FAT en un avión, por amor de Dios!”
    -- Bill Gates
     
  3. “Cualquier problema simple puede convertirse en irresoluble si se organizan las suficientes reuniones para discutirlo”
    -- Ley de los Comités de Mitchell
     
  4. “La mayoría de comentarios en el código son, de hecho, una perniciosa forma de duplicación de código”
    -- Ed Guiness
     
  5.  “Hablar es barato. Enséñame el código”
    -- Linus Torvalds
     
  6. “Programar es como jugar al golf. El tema no es meter la bola en el hoyo, sino cuántos golpes has necesitado”
    --Harlan Mills
     
  7. “La regla básica para escribir código inmantenible es especificar cada hecho en tantos lugares como sea posible y de tantas formas distintas como sea posible”
    -- Roedy Green
     
  8. “Sin requisitos o diseño, programar es el arte de añadir bugs a un archivo de texto vacío”
    -- Louis Srygley
     
  9. “Escribir el primer 90% de un programa ocupa el 90% del tiempo. El 10% restante también ocupa el 90% del tiempo, y los retoques finales otro 90% del tiempo”
    -- N.J. Rubenking
     
  10. “El propósito de la ingeniería del software es controlar la complejidad, no crearla”
    -- Pamela Zave
     
  11. El deber principal de un manejador de excepciones es quitar el error de encima al programador y ponerlo frente a la sorprendida cara del usuario”
    -- Verity Stob
     
  12. “El buen juicio viene de la experiencia, y la experiencia viene del mal juicio”
    -- Fred Brooks

Lenguajes

  1. “Lo más importante de un lenguaje de programación es el nombre. Un lenguaje no triunfará sin un buen nombre. He inventado hace poco un muy buen nombre y ahora estoy buscando el lenguaje apropiado”
    -- Donald Knuth
     
  2. “Un lenguaje de programación es de bajo nivel cuando sus programas requieren prestar atención a lo irrelevante”
    -- Alan J. Peris
     
  3. “Creo que todos los lenguajes deberían ser diseñados a la vez que se escribe una gran aplicación con él, tal y como ocurrió con C y Unix”
    -- Paul Graham
     
  4. "Cuando alguien diga ‘quiero un lenguaje de programación en el que sólo tenga que decir lo que deseo que se haga’, dadle una piruleta”
    -- Alan J. Perlis
     
  5. “Los lenguajes de programación, como las pizzas, sólo vienen en dos tamaños: demasiado grande y demasiado pequeño”
    -- Richard Pattis
     
  6. “Tratar de ser más inteligente que un compilador elimina gran parte del propósito de usar uno”
    -- Kernighan and Plauger
     
  7. “Un lenguaje que no afecte a la forma en que piensas al programar no merece la pena conocerlo”
    -- Alan J. Peris
     
  8. “Un sistema de tipos es el test unitario más efectivo y de menor coste que jamás vas a tener”
    -- Peter Hallam
     
  9. “Lo bueno de reinventar la rueda es que puedes inventarla redonda”
    -- Douglas Crockford, respondiendo a por qué se creó JSON cuando XML ya existía
     
  10. “A veces, cuando estoy escribiendo Javascript quiero agitar mis manos diciendo ‘this is bullshit!’, pero nunca puedo recordar a qué me refiero con el ‘this’”
    -- Ben Halpern

Programadores

  1. “Un mal programador puede crear fácilmente dos nuevos puestos de trabajo al año”
    -- David Parnas
     
  2. “Los desarrolladores prolíficos no siempre escriben mucho código, pero resuelven un montón de problemas. Estas dos cosas no son siempre la misma”
    -- J. Chambers
     
  3. “No puedes enseñar a los principiantes programación descendente porque ellos no saben qué parte es la que está arriba”
    -- C.A.R. Hoare
     
  4. “Cualquiera que ha perdido la noción del tiempo usando un ordenador conoce la propensión a soñar, la urgencia por hacer los sueños realidad, y la tendencia a perderse el almuerzo”
    -- Tim Berners-Lee
     
  5. “Un sistema representa la solución de alguien a un problema. El sistema no resuelve el problema”
    -- John Gall
     
  6. “No subestimes el poder de destrucción de un programador no experimentado frente a un código medianamente complejo”
    -- Raliug Amesoj
     
  7. “¿La experiencia cuenta? ¡No! No si estamos haciendo las cosas mal”
    -- W. Edwards Deming

Buenas prácticas

  1. "Si a los programadores se les pagara por eliminar código en lugar de escribirlo, el software sería mucho mejor”
    -- Nicholas Negroponte
     
  2. “La mejor forma de hacer un proyecto más rápido es empezando antes”
    -- Jim Highsmith
     
  3. “No estar en producción es gastar dinero sin hacer dinero”
    -- Kent Beck
     
  4. “Los buenos programadores usan sus cerebros, pero unas buenas guidelines nos evitan tener que hacerlo a cada momento”
    --Francis Glassborow
     
  5. “El problema de programar algo quick and dirty es que el ‘dirty’ permanece mucho tiempo después de que el ‘quick’ haya sido olvidado”
    -- Steve C. McConnell
     
  6. “Que tus aplicaciones hagan lo menos posible. Si no haces nada, pues escalar hasta el infinito”
    -- Scott Hanselman, el secreto de la escalabilidad
     
  7. “Cuando estés resolviendo problemas, escarba hasta las raíces en lugar de quedarte recortando las hojas”
    -- Anthony J. D'Angelo
     
  8. “La única ‘buena práctica’ que deberías seguir todo el rato es usar tu cerebro” 
    -- Steven Robbins
     
  9. “Cuando un sistema evoluciona, su complejidad se incrementa a menos que se trabaje para mantenerla o reducirla”
    -- Manny Lehman

Ordenadores

  1. “Si no quieres ser sustituido por un ordenador, no actúes como uno de ellos”
    -- Arno Penzias
     
  2. “Una máquina puede hacer el trabajo de cincuenta hombres ordinarios. Ninguna máquina puede hacer el trabajo de un hombre extraordinario”
    -- Elbert Hubbard
     
  3. “El peligro real no es que los ordenadores comiencen a pensar como las personas, sino que las personas comiencen a pensar como ordenadores”
    -- Sydney J. Harris
     
  4. “Mierda… alguien ha tumbado mi papelera y tengo todo el escritorio lleno de iconos”
    -- Billiam
     
  5. La pregunta no es cuándo las máquinas comenzarán a pensar, sino cuándo los hombres lo haremos”
    -- B. F. Skinner
     
  6. “Cualquier profesor que pueda ser reemplazado por un ordenador, merece que lo sea”
    -- David Thornburg
     
  7. “Escribí un anuncio para Apple Computer: Macintosh – puede que no lo hagamos todo bien, pero al menos sabíamos que el siglo iba a acabar’” 
    --Douglas Adams, sobre la ausencia del problema Y2K en Mac
     
  8. “Reiniciar es como una droga maravillosa… lo arregla casi todo”
    -- Garrett
     
  9. “Inteligencia artificial: el arte de hacer ordenadores que se comporten como los de las películas”
    -- Bill Bulko
     
  10. “Los ordenadores personales son llamados a  ejercitar muchas nuevas funciones, incluyendo el borrado de las tareas para casa que anteriormente se comía el perro”
    -- Doug Larson
     
  11. “No existe absolutamente ninguna razón para crear ordenadores tan estúpidos como la gente”
    --Nigel Jacob
     
  12. “El mejor ordenador es el hombre, y es el único que puede ser producido masivamente por trabajadores no cualificados”
    -- Wernher Magnus Maximilian
     
  13. “El ordenador es increíblemente rápido, preciso y estúpido. El nombre es increíblemente lento, impreciso y brillante. La unión de ambos es de una fuerza incalculable”
    -- Leo Cherne

Tecnología

  1. “Nuestra industria no respeta la tradición, sólo respeta la innovación.”
    -- Satya Nadella
     
  2. “El futuro ya está aquí, lo que ocurre es que no está distribuido equitativamente”
    -- William Gibson
     
  3. “Tecnología es cualquier cosa inventada después de tu nacimiento”
    -- Alan Kay
     
  4. “La innovación es lo que distingue a un líder de un follower” -- Steve Jobs
     
  5. “Microsoft ahora está hablando sobre sistemas nerviosos digitales… me pregunto cómo de nervioso estaría yo si mi sistema estuviera construido con su tecnología”
    -- Scott McNealy
     
  6. Desde teléfono hasta coches o medicina, la tecnología afecta a todos los aspectos de nuestra vida. Si puedes crear tecnología, puedes cambiar el mundo”
    -- Susan Wojcicki
     
  7. “Creo que los virus de ordenador deberían considerarse vida. Pienso que dice algo sobre la naturaleza humana que la única forma de vida que hemos creado sea puramente destructiva. Hemos creado vida a nuestra propia imagen”
    -- Stephen Hawking
     
  8. ”¿Cómo piensas hacer negocio con un buscador?”
    --- Guy Kawasaki, 1996, rechazando el puesto de CEO de Yahoo
     
  9. “Tras crecer salvajemente durante años, la informática parece estar llegando a su infancia”
    -- John Pierce
     
  10. “Intel Inside: la etiqueta de advertencia más usada del mundo”
    -- Jim Hopper
     
  11. “Todas las mayores invenciones tecnológicas creadas por el hombre –el avión, el automóvil, el ordenador… - dicen poco sobre su inteligencia, pero mucho sobre su pereza”
    -- Mark Kennedy
     
  12. “Uber, la compañía de Taxis más gran del mundo, no tiene vehículos. Facebook, el propietario de contenidos más grande del mundo, no crea contenido. Alibaba, el comercio más famoso, no tiene inventario. Y Airbnb, el proveedor de alojamiento más grande, no tiene propiedades. Algo interesante está ocurriendo”
    -- Tom Goodwin

Errores y depuración

  1. “Si tu aplicación es lenta, añade un caché. Si tu aplicación tiene errores, elimina el caché.”
    -- Art Taylor
     
  2. “La corrección es claramente la principal característica de la calidad. Si un sistema no hace lo que se supone que debe hacer, todo lo demás importa poco”
    -- Bertrand Meyer
     
  3. “Cuanto más tarda un bug en aparecer, más difícil es encontrarlo“ 
    -- Roedy Green
     
  4. “No necesito probar mis programas, tengo un módem con corrección de errores”
    -- Anónimo
     
  5. “La cosa más valiosa que puedes hacer es equivocarte. No puedes aprender nada siendo perfecto”
    -- Adam Osborne

Software

  1. "La perfección se consigue no cuando no queda nada más que añadir, sino cuando no queda nada por eliminar”
    -- Antoine de Saint Exupéry 
  2. ”Sabemos que la máquina del tiempo es imposible porque ninguna multitud trató de registrarla el día que abrió la primera oficina de patentes.”
    -- Andres Diplotti
     
  3. “Censuro la actual tendencia de pedir patentes sobre algoritmos. Hay mejores maneras de ganarse la vida que impidiendo a otras personas hacer uso de las contribuciones de uno a la informática”
    -- Donald Knuth
     
  4. “Los únicos que tienen algo que temer del software libre son aquellos cuyos productos valen incluso menos”
    -- David Emery
     
  5. “Si quieres un producto con determinadas características, debes asegurarte de que el equipo las conoce antes de empezar a desarrollarlo”
    Jim & Michele McCarthy
     
  6. “El tipo más peligroso de basura es la basura que no reconocemos”
    --Shigeo Shingo
     
  7. “Un sistema complejo que funciona siempre es una evolución de un sistema simple que funcionaba. Un sistema complejo diseñado desde cero nunca funciona ni puede arreglarse para que funcione. Hay que comenzar de nuevo, comenzando por un sistema simple que funcione”
    -- John Gall

Internet

  1. ”Recordad que el problema no es que la gente sea estúpida; el problema es que los módems son baratos”
    -- Vince Sabio
     
  2. “He calculado el tiempo total que la humanidad ha esperado para que las páginas web terminen de cargar, y compensa toda la productividad ganada por la era de la información. A veces pienso que la web es un gran complot para mantener a gente como yo lejos de la sociedad normal”
    -- Scott Adams
     
  3. “Describir Internet como la red de redes es como llamar al Space Shuttle cosa que vuela”
    -- John Lester
     
  4. “Hay tres tipos de muerte en este mundo: cerebral, cardíaca y estar desconectado de la red”
    -- Guy Almes
     
  5. “Antes de casarte con alguien deberías hacerle usar un ordenador con una conexión lenta a internet para ver quién es realmente”
    -- Will Ferrel
     
  6. “En cierto sentido, Internet es como el alcohol, pues acentúa lo que eres. Si quieres ser un solitario, puedes ser más solitario. Si quieres ser más social, te hace fácil ser más social”
    -- Esther Dyson
     
  7. “La infomación en internet está sujeta a las mismas reglas y leyes que una conversación en un bar”
    -- George Lundberg
     
  8. “Todos los libros del mundo no contienen más información que la que se transmite el vídeo en una única gran ciudad americana en un solo año. No todos los bits tienen el mismo valor”
    --- Carl Sagan
     
  9. “Pasar la tarde en la web se parece mucho a sentarse a cenar Cheetos. Dos horas más tarde tienes los dedos amarillos y se te ha pasado el hambre, pero no te has alimentado”
    -- Clifford Stoll
     
  10. “No creas nada de lo que leas por la red. Excepto esto. Bueno, supongo”
    -- Douglas Adams
¡Y esto es todo! Por si os saben a poco, ahí van los links a las entregas anteriores de la serie:
Publicado por: Variable not found.

» Leer más, comentarios, etc...

Arragonán

Semanas 355, 356 y 357

April 13, 2015 11:14 AM

Nada menos que 3 semanas acumuladas sin retro… más por falta de motivación de ponerme a escribir que por falta de tiempo para poder hacerlo. Llevo unas semanas un poco locas por varias razones y ando algo despistado, en ocasiones me cuesta concentrarme. El que estuviera de por medio la semana santa tampoco es que ayudase.

El mes de marzo lo cerramos con una nueva edición de Zaragoza.rb. Esta vez no teníamos charla organizada, hicimos la kata Harry Potter en formato randori.

Se hizo público lo que por aquí daba a conocer como el proyectoSinNombre. Quizás un día escriba sobre ello.

Durante estas semanas en SenpaiDevs hemos tenido visitas de TorresBurriel y Javi Martínez, hemos estado trabajando en el proyecto con los kohais e hicimos una nueva retrospectiva en la que volvimos a sacar algunos puntos de mejora.

Hemos seguido trabajando para el Startup Open Space, llevo menos estrés que el año pasado… lo que no significa que NO lo lleve :S.

La semana pasada celebramos el 5º aniversario de Agile Aragón. Yo hice una pequeña charla de recopilación de lo que ha pasado durante este tiempo, mientras que Néstor facilitó la retrospectiva donde salió mucha chicha, y después lo cerramos yéndonos a cenar unos cuantos.

Durante estas semanas me han llegado varias posibilidades de nuevos proyectos, bastante variopintos y cada uno a su manera con bastante buena pinta.

Mientras que en los actuales:

  • Le hemos metido buen apretón a Mosica con “mi primo” Guillermo. Tanto a la web como a la aplicación móvil (pronto para ios y android), ya tenemos afiliados con ticketea, mejoré la parte de backoffice y me dediqué a automatizar algunas tareas.
  • En One-stop estuve adelantando bastante trabajo, buena parte del proyecto está finiquitado y ya está en entorno de staging. Aunque aún queda una parte del proyecto importante y con cierto riesgo, espero que no se alargue más que un par de semanas el poder finiquitarlo.
  • Tuve reunión para retomar la migración de la tienda online de Bichomanía, por lo que mi dedicación para ello tiene que aumentar durante estas semanas.
  • Estuve dedicando tiempo para tratar varias cuestiones tanto de mhop como de outreachbox, aunque nada que ver con la parte de desarrollo.
  • También tuve alguna reunión relacionada con minchador y viendo algunos pequeños cambios a implementar para los restaurantes.

Buena semana.

» Leer más, comentarios, etc...

Poesía Binaria

Creando un controlador en Magento (paso a paso)

April 13, 2015 08:05 AM


Hace un tiempo comentábamos cómo crear un plugin para Magento. Ahora, vamos a completar ese plugin creando un controlador (y nos metermos ligeramente con las plantillas) para crear algo funcional dentro de nuestra instalación de Magento.

Antes de nada, advertir que el tema de las mayúsculas y minúsculas tanto en nombres de archivos como nombres de módulos es un poco delicado, por lo que si queremos curarnos en salud, debemos elegir un nombre lo más sencillo posible. Y, sobre todo, mientras estés trabajando desactiva cachés o, al menos, bórralos a menudo. Vamos a estar haciendo cambios constantemente y tal vez no aparezcan por eso.

Creando un controlador

Esta es la parte más sencilla. Sólo tenemos que crear en el directorio de nuestro plugin el directorio “controllers” en minúscula. Si en el post anterior veíamos que nuestro módulo estaba en app/code/local/nuestraEmpresa/nuestroModulo/ , debemos crear app/code/local/nuestraEmpresa/nuestroModulo/controllers.
. En el ejemplo la empresa se llamará Poesia y el Plugin HolaMundo (aprovechamos y metemos una mayúscula, para ver cómo podemos hacerlo).

Lo primero será editar el archivo de configuración de nuestro plugin app/code/local/nuestraEmpresa/nuestroModulo/etc/config.xml, he incluido el archivo completo con una nota en la que podemos ver las líneas nuevas:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?xml version="1.0" encoding="UTF-8"?>
<!--
Opcionalmente podemos poner un comentario contando qué hace nuestro módulo, nuestra web,
información sobre la licencia, etc
-->
<config>
    <modules>
        <Poesia_HolaMundo> <!-- namespace_modulo -->

            <!-- Esta es la versión de nuestro módulo -->
            <version>0.0.1</version>

        </Poesia_HolaMundo>
    </modules>
<!-- Lo que necesitamos para utilizar los controladores -->
    <frontend>
      <routers>
    <holaMundo>
      <use>standard</use>
      <args>
        <module>Poesia_HolaMundo</module>
        <frontName>hm</frontName>
      </args>
    </holaMundo>
      </routers>
    </frontend>
<!-- Lo que necesitamos para utilizar los controladores -->
</config>

En este caso, la etiqueta <holaMundo> corresponde con el nombre de nuestro módulo, aunque la primera sea mayúscula, aquí empezará en minúscula (camelCase empezando en minúscula). Luego, dentro de <args> el módulo, es NuestraEmpresa_NuestroModulo y el frontname será el nombre de nuestro módulo en la URL. Por lo tanto todos los controladores estarán a partir de http://urldenuestromagento.ext/hm/xxx.

Dentro de controllers creamos un archivo que se llama nuestrocontroladorController.php. En el ejemplo, como queremos hacer un sistema de postventa, lo llamaremos PostVentaController.php. Ese archivo debe extender Mage_Core_Controller_Front_Action (podemos extender otros para algunos casos especiales). Dentro de los controladores, crearemos acciones, debemos pensar que un controlador puede lanzar varios tipos de acciones, por ejemplo, un controlador para un formulario podría querer lanzar la vista del formulario (precargando algunos valores), luego procesar los datos enviados y validar las entradas del usuario por AJAX, por lo que tendríamos tres acciones (por supuesto que podemos tener una sola acción, pero separamos nuestro código y diferenciamos bien las partes).

Las acciones, por defecto se llamarán cuando accedamos a http://urldenuestromagento.ext/plugin/controlador/accion y éstas llamarán a un método de nuestra clase controlador (PostVentaController). En principio, vamos a definir una acción especial que se cargará cuando hagamos http://urldenuestromagento.ext/plugin/controlador/ que será la IndexAction. En este ejemplo, crearemos un controlador con dos métodos, el indexAction y el testAction para http://urldenuestromagento.ext/plugin/controlador/ y http://urldenuestromagento.ext/plugin/controlador/test respectivamente.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class Poesia_HolaMundo_PostVentaController extends Mage_Core_Controller_Front_Action
{
  function indexAction()
  {
    echo "Estamos en el index";
  }

  function testAction()
  {
    echo "Estamos en test";
  }
}

Si accedemos a las URLs anteriormente mencionadas veremos que los controladores se cargan bien. Aunque sólo se cargan esos controladores, sin plantillas ni bloques ni nada. Por lo que debemos trabajar un poco más. En nuestro ejemplo del módulo PostVenta, podremos acceder a http://urldenuestromagento.ext/hm/postVenta/ o a http://urldenuestromagento.ext/hm/PostVenta/ aunque no a http://urldenuestromagento.ext/hm/postventa/.

Haciendo que nuestras acciones usen plantillas

Para empezar con nuestras plantillas. Vamos a hacer una configuración completa del sistema, creando un nuevo archivo de layout (podemos aprovechar alguno de los que ya existen, pero lo suyo es que todo quede bien separado y diferenciado, ya que el módulo debe ser totalmente independiente).

Volvemos a editar el archivo app/code/local/nuestraEmpresa/nuestroModulo/etc/config.xml para decirle que busque nuestro archivo XML de layout, que se llamará poesia.xml (pego el archivo entero, pero tendremos un comentario que indicará las novedades):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<!--
Opcionalmente podemos poner un comentario contando qué hace nuestro módulo, nuestra web,
información sobre la licencia, etc
-->
<config>
    <modules>
        <Poesia_HolaMundo> <!-- namespace_modulo -->

            <!-- Esta es la versión de nuestro módulo -->
            <version>0.0.1</version>

        </Poesia_HolaMundo>
    </modules>
    <frontend>
<!-- Lo que necesitamos para utilizar los controladores -->
      <routers>
    <holaMundo>
      <use>standard</use>
      <args>
        <module>Poesia_HolaMundo</module>
        <frontName>hm</frontName>
      </args>
    </holaMundo>
      </routers>
<!-- Lo que necesitamos para utilizar los controladores -->
<!-- Lo que necesitamos para el layout y las plantillas -->
      <layout>
        <updates>
      <holamund>
        <file>poesia.xml</file>
      </holamundo>
        </updates>
      </layout>
<!-- Lo que necesitamos para el layout y las plantillas -->
    </frontend>
</config>

En este caso, el tag <holamundo> indicará el módulo al que se hace referencia (¡todo en minúsculas esta vez!)

El archivo de layout lo podemos crear válido para todos los temas o sólo para un tema particular, dependiendo si está en app/design/frontend/base/default/layout/poesia.xml o si lo colocamos en app/design/frontend/default/nuestrotema/layout/poesia.xml; si el archivo se encuentra en los dos sitios, se cogerá el específico para el tema. Es más, en ese poesia.xml se pueden llamar plantillas que se buscarán en app/design/frontend/default/nuestrotema/, pero si no se encuentran ahí, se buscarán en app/design/frontend/base/default/.

Vamos a crear un archivo poesia.xml básico:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<layout version="0.1.0">
    <default>
    <reference name="root">
        <action method="setTemplate">
        <template>page/1column.phtml</template>
        </action>
    </reference>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/index.phtml"></block>
    </reference>
      </default>
</layout>

Aquí especificamos que la plantilla base para nuestras páginas será page/1column.phtml (podemos buscarla en base o en nuestro tema). También decimos que el contenido contendrá un bloque básico (core/template) cuya plantilla será holamundo/index.phtml.

Ahora tenemos que decirle a las acciones de nuestro controlador que deben cargar la plantilla:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class Poesia_HolaMundo_PostVentaController extends Mage_Core_Controller_Front_Action
{
  function indexAction()
  {
    $this->loadLayout();    
    $this->renderLayout();
  }

  function testAction()
  {
    $this->loadLayout();    
    $this->renderLayout();
   }
}

Ahora, tanto test, como index, cargarán la plantilla básica y sus contenidos, ya es cosa vuestra programar las acciones. Aunque, ahora mismo los dos están utilizando la misma plantilla que podrá estar en app/design/frontend/base/default/template/holamundo/index.phtml o en app/design/frontend/default/tema/template/holamundo/index.phtml

Personalizando las plantillas de nuestras acciones

Si queremos que cada acción utilice una plantilla diferente, debemos especificarlo en el xml de layout, en nuestro caso, poesia.xml de la sigueinte manera:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0"?>
<layout version="0.1.0">
  <holamundo_postventa_index>
    <reference name="root">
      <action method="setTemplate">
    <template>page/1column.phtml</template>
      </action>
    </reference>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/index.phtml"></block>
    </reference>
  </holamundo_postventa_index>
  <holamundo_postventa_test>
    <reference name="root">
      <action method="setTemplate">
    <template>page/2columns-left.phtml</template>
      </action>
    </reference>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/test.phtml"></block>
    </reference>
  </holamundo_postventa_test>
</layout>

En este caso, el nombre del plugin, controlador y acción tiene que ir completamente en minúsculas. Aquí hemos utilizado una plantilla base (root) diferente para cada acción, pero podemos utilizar una plantilla común y variar sólo el content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0"?>
<layout version="0.1.0">
  <default>
    <reference name="root">
      <action method="setTemplate">
    <template>page/1column.phtml</template>
      </action>
    </reference>
  </default>
  <holamundo_postventa_index>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/index.phtml"></block>
    </reference>
  </holamundo_postventa_index>
  <holamundo_postventa_test>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/test.phtml"></block>
    </reference>
  </holamundo_postventa_test>
</layout>

Además, podemos incluir CSS o JS personalizados, que podrán ser cargados en la parte superior de la página:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0"?>
<layout version="0.1.0">
  <default>
    <reference name="head">
      <!-- CSS y JS propios -->
      <action method="addJs">
        <script>holamundo/holamundo.js</script> <!-- se buscará en [magentoroot]/js -->
      </action>

      <action method="addCss">
    <!-- se buscará en [magentoroot]/skin/frontend/default/[tema]/css/ -->
    <!-- o en [magentoroot]/skin/frontend/base/default/css/ -->
        <stylesheet>css/holamundo.css</stylesheet>
      </action>
    </reference>
    <reference name="root">
      <action method="setTemplate">
    <template>page/1column.phtml</template>
      </action>
    </reference>
  </default>
  <holamundo_postventa_index>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/index.phtml"></block>
    </reference>
  </holamundo_postventa_index>
  <holamundo_postventa_test>
    <reference name="content">
      <block type="core/template" name="main_block" template="holamundo/test.phtml"></block>
    </reference>
  </holamundo_postventa_test>
</layout>

Chuleta rápida para respuestas de acciones

Este pequeño anexo nos ayudará a generar posibles respuestas de diferente índole desde nuestras acciones. Por ejemplo:

Devolver un 404

Esto nos sirve, por ejemplo para evitar que el usuario vea que ahí hay algo. Tal vez sea un método que sólo determinados usuarios pueden utilizar, o que usamos sólo en modo desarrollo, por ejemplo nuestro indexAction() se quedaría así:

1
2
3
4
  function indexAction()
  {
    $this->norouteAction();
  }

y evitaremos que alguien entre directamente a esa acción.

Devolver mensajes de éxito, error o advertencia

Para esto, tenemos que hacer lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class Poesia_HolaMundo_PostVentaController extends Mage_Core_Controller_Front_Action
{
  function indexAction()
  {
    Mage::getSingleton('core/session')->addSuccess($this->__('Esto devolverá éxito'));
    $this->loadLayout();    
    $this->renderLayout();
  }

  function testAction()
  {
    Mage::getSingleton('core/session')->addWarning($this->__('Esto devolverá advertencia'));
    $this->loadLayout();    
    $this->renderLayout();
   }

  function errorAction()
  {
    Mage::getSingleton('core/session')->addError($this->__('Esto devolverá error'));
    $this->loadLayout();    
    $this->renderLayout();
   }
}

Warning! En algunos temas, los estilos de Warning no están definidos.
Es una buena técnica utilizar el método $this->__() ante cualquier mensaje que demos, ya que lo haremos pasar por el traductor y podrá ponerse en cualquier idioma (siempre que nos curremos las traducciones).

Redirecciones

Basta con llamar a $this->_redirectUrl() con la dirección que queremos llamar (esto casi casi puede dar para otro post):

1
2
3
4
  function errorAction()
  {
    $this->_redirectUrl('http://la_url_que_quiero.com/');
   }

o por ejemplo:

1
2
3
4
  function errorAction()
  {
    $this->_redirectUrl(Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB));
   }

para redirigir a la página principal de la tienda.

Una ayuda es sacar la URL desde la que venimos con: Mage::helper(‘core/http’)->getHttpReferer();

Conocer la petición

Por último, un detalle importante es conocer la petición que ha hecho el usuario cuando ha cargado la página. Por ejemplo, si ha enviado un formulario. Siguiendo este supuesto, dentro del controlador podemos cargar dicha petición en un objecto, ver si es una petición tipo POST y analizar algún parámetro enviado con dicho método:

1
2
3
4
5
6
7
8
  function sendFormAction()
  {
    $request = $this->getRequest();
    if (!$request->isPost())
       return $this->_redirectUrl(Mage::getBaseUrl());
   
    $parametropost = $request->getPost('nombreparametro');
  }

The post Creando un controlador en Magento (paso a paso) appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 194

April 13, 2015 07:05 AM

Enlaces interesantesAhí van los enlaces recopilados durante la semana pasada, espero que os resulten interesantes :-)

.Net

ASP.NET

Azure / Cloud

Conceptos/Patrones/Buenas prácticas

Html/Css/Javascript

Visual Studio/Complementos/Herramientas

Otros

Publicado en Variable not found

» Leer más, comentarios, etc...

Koalite

La inversión de dependencias no es (sólo) lo que tú piensas

April 13, 2015 05:06 AM

Ah, SOLID. Los principios SOLID. Esos principios, desconocidos por unos, sobrevalorados por otros, que se supone que deberían servirnos para desarrollar mejor software. Se ha escrito mucho sobre estos principios, pero a veces nos quedamos más con la implementación concreta (el patrón de diseño, la recetilla a aplicar) que con la idea subyacente.

Siempre he dicho que me gustan más los conceptos que los detalles, por eso en este post quiero profundizar sobre uno de los principios SOLID, el principio de inversión de dependencias, desde un punto de vista más general que el típico “cómo implementar inversión de dependencias en el framework X”.

Qué es la inversión de dependencias

Tradicionalmente, a la hora de definir las dependencias entre los módulos de un sistema, y especialmente si era un sistema basado en capas (esos N-Layer de infausto recuerdo), la dependencia entre los distintos componentes de un sistema era algo así:

n-layer-deps

… que en código se convirtía en una cosa como ésta:

// Assembly DataAccessLayer.dll
public class CustomerDAO {}

// Assembly BusinessLogicLayer.dll, que referencia DataAccessLayer.dll
using DataAccessLayer;
public class CustomerBO { 
    private CustomerDAO dao;
}

Avanzando unos años en el tiempo (del 2002 al 2007 más o menos) y aplicando el principio de inversión de dependencias, aunque no tengamos muy claro por qué ni para qué, lo que hacemos es invertir la dependencia entre el paquete que contiene la lógica de negocio y el paquete que contiene la lógica de persistencia.

Usando terminología actualizada, llegamos al siguiente grafo de dependencias:

n-layer-inverted-deps

Para cambiar la dirección de la dependencia entre la lógica de negocio y la lógica de persistencia, los pasos suelen ser siempre los mismos. Se definen una serie de interfaces en el paquete con la lógica de negocio y se implementan con clases declaradas en el paquete de persistencia.

Algo así:

// Assembly Domain.dll
public interface ICustomerRepository {}
public class CustomerService {
    private ICustomerRepository repository;
}

// Assemmbly Persistence.dll, que referencia Domain.dll
using Domain;
public class CustomerRepository : ICustomerRepository {}

Para hacer luego el montaje de todo esto, entra en juego un patrón muy relacionado con la inversión de dependencias: la inyección de dependencias que nos permite componer la aplicación (con contenedor o sin él) manteniendo las dependencias en la dirección adecuada.

Y ya está. Perfecto. Ya hemos aplicado el principio de inversión de dependencias, ya tenemos código SOLID-compliant, podemos sentirnos clean coders, comprarnos una pulsera que lo demuestre (en serio, esas cosas existen) y asunto resuelto.

Puede que suene exagerado, pero os aseguro que más de una vez al preguntar sobre este tema la respuesta que he obtenido es más o menos esa: “sí, hombre, inversión de dependencias… eso es lo de que defines el interfaz en el dominio y luego el repositorio en otro proyecto”.

Qué es, en serio, la inversión de dependencias

Si colgarte la medalla de aplicar mecánicamente principios SOLID no es suficiente para ti y quieres saber algo más (enhorabuena, es un enfoque mucho mejor), podemos empezar por ver la definición original de inversión de dependencias que dio Robert C. Martin en el año 2003 en su libro “Agile Software Development: Principles, Patterns, and Practices”, la cual está compuesta por los siguientes dos puntos:

  • Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones.
  • Las abstracciones no deben depender de detalles, son los detalles los que deben depender de abstracciones.

En una traducción (un tanto libre, lo admito) a lenguaje coloquial podríamos resumirlo en:

Que las cosas importantes no dependan de cosas menos importantes.

Qué significa la inversión de dependencias

En lugar de quedarnos en la recetilla de cómo aplicar el principio de inversión de dependencias que veíamos antes, vamos a intentar profundizar en la idea subyacente, las implicaciones que tiene y ver qué más cosas podemos extraer de él.

¿Cuál es el motivo de depender de abstracciones? ¿Por qué no queremos que las abstracciones dependan de los detalles, sino que sea al revés? ¿Qué extraña razón nos impulsa a que el centro de nuestro sistema sean las abstracciones?

Hay varios motivos (y mucha literatura al respecto en internet), pero uno de los más importantes es la estabilidad de cada componente. No me refiero a la estabilidad en el sentido de que no contenga errores, sino la estabilidad en el tiempo. La menor frecuencia de cambio.

Las abstracciones que introducimos y de las que dependemos tienden a ser más estables en el tiempo precisamente porque las abstracciones capturan la esencia del sistema, y no los detalles accidentales. Puede que cambie el API usada para acceder al servicio de validación de tarjetas de crédito, pero el concepto “validar una tarjeta de crédito” es mucho más estable en el tiempo.

Al aplicar el principio de inversión de dependencias estamos haciendo que las cosas que cambian más (las implementaciones concretas) dependan de las cosas que cambian menos (las abstracciones), haciendo nuestro sistema más resistente a los cambios. Evitamos que los cambios en esas partes más inestables se propaguen hacia el resto del sistema, ya que el resto del sistema no depende de ellas.

Esta misma idea de hacer que las dependencias apunten hacia componentes más estables, podemos aplicarla no sólo entre componentes “técnicos”, como pueden ser una base de datos o un servicio web, sino también entre conceptos de nuestro modelo.

Un caso práctico sería a la hora de elegir aggregate roots. Imagina que tenemos una versión extremadamente simplificada del típico modelo de facturas:

invoice-model

Ahora, queremos que cada factura pueda llevar asociado un vale de regalo, para aquellos casos en que queremos fidelizar el cliente ofreciéndole un descuento. Por la forma en que hemos expresado el nuevo requisito, “que cada factura pueda llevar asociado”, parece que la solución lógica sería pasar un modelo así:

invoice-voucher-model

Éste es un modelo válido y que seguramente funcione bien en la mayoría de los casos pero, ¿es mejor o peor que este otro?

invoice-model-inverted

Si pensamos en el principio de inversión de dependencias, deberíamos depender siempre en la dirección de la estabilidad, es decir, las cosas menos estables depender de las más estables. ¿Qué es más probable que cambie en este caso, el concepto de factura o el sistema de fidelización? En general, el departamento de marketing cambiará de idea más rápido que la legislación sobre cómo emitir una factura, por lo que parece razonable utilizar este último modelo.

Al igual que hablamos del vale de regalo, podríamos hablar de los pagos asociados a la factura. ¿Es mejor que la factura tenga una dependencia sobre los pagos o que sean éstos los que dependen de la factura? Nunca hay una respuesta directa a este tipo de preguntas, y hay más factores a tener en cuenta (rendimiento al acceder al sistema de persistencia, transaccionalidad, casos de uso, etc.), pero uno de los factores que debemos (o al menos podemos) tener en cuenta es el principio de inversión de dependencias.

Si hacemos que las partes más centrales y estables del sistema empiecen a depender de toda nueva funcionalidad que va a apareciendo, estamos perdiendo estabilidad en áreas que necesitamos que sean seguras. Es la misma idea que usábamos con las capas, pero llevada a funcionalidades/conceptos/bounded-context/áreas/cómo-lo-quieras-llamar.

Esto presenta una ventaja adicional, y es que si evitamos que todas las dependencias emanen desde dos o tres clases “centrales” de nuestro sistema, podremos conseguir diseños menos acoplados y no caeremos en antipatrones como el God Object.

Resumen

Tener código SOLID-compliant para presumir con tus amigos en twitter es fácil. Sólo necesitas aprenderte unas cuantas técnicas para aplicar los principios SOLID y quedarás bien. Además, no nos engañemos, en general este tipo de técnicas pueden ayudarte a escribir mejor código, así que tampoco es malo que lo hagas.

Lo bueno de los prinpicios SOLID es que, pese al abuso que se hace últimamente de ellos, se derivan de unas ideas muy básicas que podemos aplicar en ámbitos más generales que los ejemplos típicos. Si intentas profundizar en estas ideas subyacentes, podrás comprender mejor los problemas que supone desarrollar software y estarás en condiciones de buscar mejores soluciones para estos problemas.

Posts relacionados:

  1. Inyección de dependencias en Javascript (y otros lenguajes dinámicos)
  2. Usa property injection para dependencias ambientales
  3. Dependencias binarias y dependencias de código fuente

» Leer más, comentarios, etc...

proyectos Ágiles

La empresa Ágil

April 12, 2015 05:00 PM

A continuación se muestran los principios básicos de funcionamiento y organizativos de una empresa ágil.

 empresa-agil-principios

 

 

equipos-multi-disciplinares

 

equipos-auto-organizados

 

 equipos-estables

conectar-no-coordinar.jpg

 principios-trabajo-equipo

simplicidad.jpg 

ley-conway 

celulas-autonomas

 organizacion-flujo-valor

 celulas-responsables

aprender-mejorar

manager-facilitador-organizativo

 lugar-motivante

motivacion-intrinseca

mundo-complejo

 

agile-menor-complejidad

 


 

 

Artículos relacionados

» Leer más, comentarios, etc...

Blog Bitix

Productividad y errores de compilación con Apache Tapestry

April 10, 2015 06:00 PM

Apache Tapestry

Hace ya unos años comentaba varios motivos para elegir Apache Tapestry como framework para desarrollar una aplicación o página web. Entre las varias razones comentaba la productividad como característica destacada. Uno de los motivos es esta productividad era por la alta reutilización de código que se puede conseguir al usar los componentes múltiples veces en un mismo proyecto o en diferentes proyectos creando una librería de componentes como comento más detalladamente en el libro PugIn Tapestry. Otra parte de la productividad que comentaba más ligeramente era poder detectar de forma rápida errores de compilación no solo en el código Java a través del IDE sino porque con Tapestry es posible detectar errores de compilación en todas las plantillas tml que generan el html fácil y rápidamente con un botón sin tener que probar manualmente toda la funcionalidad. El tema de este artículo es mostrar más en detalle como detectar los errores de compilación en las vistas con este framework.

Java

Por «errores de compilación» me refiero a ese tipo de erorres que hace el código ni siquiera pueda ser interpretado correctamente por el computador, puede ser porque falta un import, un nombre de variable, propiedad o método mal puesto y que no existe… Poder detectar errores de compilación fácilmente en toda la aplicación es tremendamente útil y evitará que lleguen a producción con las consiguientes molestias para los usuarios y que posteriormente tengamos que dedicar tiempo a corregirlos cuando hemos perdido el contexto de las modificaciones hechas. También tendremos más seguridad de que no introducicmos errores al hacer refactorizaciones importantes en el código. Los errores de compilación suelen ser fáciles y rápidos de corregir pero igualmente pueden impedir totalmente el uso de la aplicación. Cuando antes detectemos los errores más fácilmente los corregiremos y más productivos seremos ya que evitaremos corregirlos en un momento posterior en que costará más tiempo y esfuerzo, además de tener que realizar un nuevo despliegue con los cambios corregidos que dependiendo del tiempo que nos lleve puede suponer otro problema.

La errores de compilación no depende de escribir pocas lineas de código o ahorarnos pulsar unas cuantas teclas, mi experiencia con los lenguajes dinámicos como Groovy y el framework Grails es que se producen ocasionales pero constantes errores de compilación en el código Groovy y en las plantillas de vistas gsp. En parte estos errores se pueden detectar teniendo teses pero la realidad es que en pocos proyectos hay una cobertura del 100% del código sobre todo para esas partes en las que «seguro no se dan errores» o poco relevantes que no merece la pena hacerlos, tener una cobertura completa del código exige tener muchos teses y datos de prueba que los ejerciten para pasar por todas las combinaciones de condiciones y bucles, para detectar errores en las vistas también deberíamos hacer teses y esto ya no suele ser tan habitual hacerlo. Y de forma similar esto se puede extender a algunas otras combinaciones de lenguajes y frameworks web por sus características similares. Si en el proyecto solo participa una persona o el proyecto es pequeño como suele ocurrir en las pruebas de concepto con las que solemos divertirnos el número de errores no debería ser muy elevado ya que el código estará bajo control por esa persona pero cuando en un proyecto real en el que participan unos cuantos programadores haciendo continuamente modificaciones el número de errores de compilación pueden producirse y se producirán en producción. También hay que tener mucho cuidado en merges con conflictos, reemplazos grandes o proyectos grandes con muchos archivos ya que en uno complicado es fácil dejar un código que produce errores de compilación, en un lenguaje dinámico más por no tener la ayuda del compilador que nos avise de los mismos, tambien hay que resistir la tentación de hacer cambios sin probarlos confiando en que no introduciremos errores.

Con Java y un IDE podremos detectar los errores de compilación que en un lenguaje dinámico solo observaremos en tiempo de ejecución. En Tapestry además podemos detectar los errores de compilación en las plantillas tml que generan el contenido html con un botón en la página Dashboard que ofrece incorporada Tapestry. Usando como ejemplo la aplicación que hice para el libro PlugIn Tapestry vamos a ver como detectar estos errores. De forma intencionada introduciré un error en la página que muestra el detalle de un producto en el mantenimiento CRUD del ejemplo. En vez de producto.nombre introduciré el error de compilación poniendo producto.nombra, nombra es una propiedad que no existe en la clase Producto, error que solo detectaremos después de crear un producto en otros frameworks al ejercitar el código pero que en Tapestry detectaremos también desde la página Dashboard. Por otra parte dado que en Tapestry las plantillas tml son xml válido si una etiqueta está mal balanceada también nos avisará.

<noscript><pre><code>... &lt;t:form t:id=&quot;form&quot; context=&quot;producto.id&quot; validate=&quot;producto&quot; clientValidation=&quot;none&quot; class=&quot;well&quot; role=&quot;form&quot;&gt; &lt;t:errors class=&quot;literal:alert alert-danger&quot; /&gt; &lt;t:delegate to=&quot;botonesEdicionBlock&quot;/&gt; &lt;div style=&quot;margin-top: 10px;&quot;&gt; &lt;div class=&quot;form-group&quot;&gt; &lt;t:label for=&quot;nombre&quot; /&gt; &lt;div class=&quot;controls&quot;&gt; &lt;input t:type=&quot;textfield&quot; t:id=&quot;nombre&quot; value=&quot;producto.nombra&quot; size=&quot;100&quot; label=&quot;Nombre&quot; /&gt; &lt;/div&gt; &lt;/div&gt; ...</code></pre></noscript>

Entrando a la página Dashboard y pulsando el botón Load all pages detectaremos el error sin necesidad de crear un producto. El error es el siguiente que nos indicará claramente en que página o componente se ha producido el error y una descripción bastante clara de la causa del problema.

En la imagen con el mensaje del error se puede ver de forma muy detallada cual es la causa, nos indica que el error está en la página admin/Producto y que la clase es.com.blogspot.elblogdepicodev.plugintapestry.Producto no tiene una propiedad llamada nombra, con este mensaje rápidamente nos damos cuenta del error de escritura que hemos cometido, corregirlo basta con sustituir nombra por nombre y pulsando de nuevo el botón Load all pages comprobamos que no hay más errores en esa misma página o ninguna otra de la aplicación.

Los errores en producción son un problema para los usuarios de la aplicación que no podrán trabajar normalmente y para la productividad de los desarrolladores ya que habremos perdido el contexto de los cambios causantes del fallo y nos costará más corregirlos. En caso de que se nos escape algún error la página de Excepcion nos dará información detallada y un mensaje que suele ser bastante descriptivo por si solo para descubrir donde está el bug. Otro aspecto que ayuda a la productividad y que ya incorporan varios frameworks es la recarga de clases, en Tapestry es posible para los artefactos del framework (páginas, componentes y servicios, recursos i18n, imágenes, estilos css), sí, incluido código Java, con lo que tenemos las ventajas de los lenguajes de scripting y la ayuda del compilador para detectar errores inmediatamente, lo mejor de ambas opciones sin sus debilidades.

Por supuesto, no evitaremos tener otro tipo de errores en la aplicación pero al menos los de compilación si podremos detectarlos, un error habitual que se puede seguir produciendo son los NullPointerException (NPE) pero que con las novedades introducidas en Java 8 y usando la clase Optional también deberíamos poder evitarlos. Para mi esto es una gran ayuda tanto para la productividad como para aún mejor evitar que lleguen errores a producción.

Si quieres conocer más características interesantes de Apache Tapestry puedes descargarte el libro gratuito PlugIn Tapetry. El código fuente completo del ejemplo está uno de mis repositorios de GitHub.

Referencia:
Libro PlugIn Tapestry
Página Dashboard de Apache Tapestry
Artículos sobre Apache Tapestry[alfresco]: http://www.alfresco.com/

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

European MS-DOS

April 09, 2015 08:49 AM

A decir había oído hablar de las versiones multitarea de MS-DOS, pero pensé que nunca llegaron a estar disponibles. Sin embargo, no fue así. De hecho el proyecto MS-DOS 4 fue anunciado en 1986, y algunos manufacturadores europeos como SMT Goupil e International Computers Limited (ICL) se interesaron por él, de ahí que se le conozca también como European MS-DOS. Partía de un código base de MS-DOS intermedio entre la 3.1 y la 3.2 de 1987, al que añadía multitarea preventiva en modo real 8088/8086, y un programa que permitía cambiar de una a otra, el Session Manager: sm.exe. Sin embargo, IBM, lo rechazó, y optó por continuar con la linea tradicional de PC-DOS 3.x, lanzando la versión 3.3, por lo que en 1988, Microsoft decidió entregar la versión multitarea para cumplir con los acuerdos de los OEM, manteniendo su versión interna de 4.00. De esta forma, MS-DOS 4.00M, se [...]

» Leer más, comentarios, etc...

Poesía Binaria

Transferir una imagen de disco a través de la red. Bash y más

April 08, 2015 08:29 AM


Foto: nrkbeta Flickr (CC-by)

Todo surgió cuando quería cambiar el disco duro de mi mediacenter. El disco duro lo tenía en mi ordenador de trabajo y el mediacenter (que hace también las veces de router/firewall y demás) no podía desenchufarlo. Es verdad que para un disco duro montado y activo no es la mejor forma, pero ya puestos, quería hacer el experimento, por lo que elegí algunas particiones que no tenían demasiada actividad (que luego fsck se encargue :) )

Para lo que sí puede servir es para crear imágenes de discos duros y transmitirlas a un servidor central para su almacenaje, ya sea por problemas de sitio, que no tengas espacio suficiente en algún dispositivo externo, o porque por seguridad se quiere transmitir a un servidor remoto o también, porque se tengan que instalar muchos ordenadores con configuraciones parecidas y, una vez configurado uno (ya sea con Windows, o cualquier UNIX), los configuramos todos desde aquí.

Eso sí, para ejecutar esto necesitamos Bash, dd (que suele con los *nix), pv (podemos pasar de el, pero se agradece), bzip2 (para comprimir) y netcat (para transmitir). ¡Manos a la obra!

¡ Tened cuidado cuando estéis probando esto ! ¡ Podéis escribir directamente en el disco y perder información !

En la máquina destino: Servidor

En la máquina donde queremos copiar la imagen. El destino, hará de servidor (podríamos invertir los papeles). En esa máquina (suponiendo que el disco destino sea (/dev/sdd1) y que el puerto que queremos el 19000), en un terminal, escribiremos esto:

1
$ nc -l 19000 | bzip2 -d | sudo dd bs=16M of=/dev/sdd1

En esta línea:

  • nc (netcat) será el encargado de la transmisión de datos, con -l 19000 lo ponemos en modo escucha por el puerto 19000
  • bzip2 será el programa de compresión encargado de descomprimir (para eso el -d)
  • dd escribirá en el dispositivo (le ponemos sudo porque esta operación requerirá privilegios de escritura en dicho dispositivo), con bs=16M especificamos el tamaño del bloque, y of=/dev/sdd1 especifica el dispositivo.

Si queremos que se almacene en un archivo directamente, sin escribir en ningún dispositivo:

1
$ nc -l 19000 | bzip2 -d > destino.bz2

En la máquina origen: cliente

Esta imagen será la que emitirá la imagen, se conectará con el host servidor, la comprimirá y se la pasará. Nuestro dispositivo de origen será /dev/sda1 y la máquina con la que conectaremos 192.168.0.20:

1
$ ORIGIN=/dev/sda1 sudo dd bs=16M if="$ORIGIN" | pv -s $(lsblk -n -b -o SIZE "$ORIGIN")  | bzip2 -c | nc 192.168.0.20 19000

En este caso:

  • ORIGIN=/dev/sda1 : Lo ponemos para no tener que repetir /dev/sda1 en la instrucción y evitar fallos del copia y pega
  • dd : Como antes, es el encargado de interactuar con el disco, como ahora extraemos información de él (of=”$ORIGIN”), en este caso es lo mismo que of=/dev/sda1
  • pv : Nos indicará el progreso, ¿ cuántos bytes lleva copiados ? creará una barra de progreso que podemos mirar para ver cuánto queda. Es muy útil porque la transmisión de un disco duro por red es muy lenta y queremos saber cuánto queda. Con -s especificamos el tamaño que lo calcularemos con lo siguiente:
  • lsblk : Extrae información de un dispositivo de bloques, tiene una salida compleja, por eso, con -n le quitamos encabezados, con -b especificamos la salida en bytes, con -o SIZE decimos que sólo queremos que nos diga el tamaño del dispositivo, y “$ORIGIN” indicará el dispositivo, que aquí es /dev/sda1 (si queremos podemos poner esto directamente). Además, todo está entre $(…) para pasar el valor resultante al argumento -s de pv.
  • bzip2 : será el compresor esta vez, por eso -c.
  • nc : se encarga de la transmisión por red, conectará con el host 192.168.0.20 y el puerto 19000

¡Y listo! Pasado un rato, hemos transmitido la imagen de disco que necesitábamos.

The post Transferir una imagen de disco a través de la red. Bash y más appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin