Didac Lee en Iniciador Sevilla

October 10th, 2009

Ayer, 8 de octubre de 2009, asisti a otra reunión del grupo Iniciador Sevilla, donde tuve el placer de conocer e intercambiar unas palabra con Didac Lee. Este joven de treinta y pocos años nos hablo de su carrera como emprendedor en empresas de tecnologia, contándonos no sólo lo bien que funcionan sus empresa y lo bonito que se ve todo, no; nos contó y detallo también los fracasos que ha tenido, los problemas con socios no adecuados y como consiguio seguir adelante luchado por sus sueños.

Me impresiono mucho, ya que es el primer ponente que veo en una reunión de este tipo que no viene a hacer publicidad de sus negocios, si no que vino a lo que se esperaba de él, como consiguió con un escaso capital de 3 millones de las antiguas pesetas (hoy unos 18.000 euros) poner en marcha su primer negocio, cubrir gastos, reinvertir en nuevos proyectos, meter la pata varias veces en proyectos sin futuro y salir adelante.

Luego, tomando una cervecilla en un bar cercano, cruzamos algunas palabras que me descubrio a una persona sencilla y accesible.

Desde aqui, mis felicitaciones a Didac por su ponencia y por su carrera.

Miedo a comprar & Cultura del currito

July 15th, 2009

Comentaba con mi amigo Gabri, reflexionando sobre los problemas económicos que está produciendo esta mal llamada crisis, que no se vende nada, pero más bien pienso que el problema no está en vender, si no que existe un miedo a realizar cualquier inversión o compra debido en gran medida a la incertidumbre provocada por la incapacidad de nuestros gobernantes de crear un clima de confianza y seguridad que permita la recuperación económica.

Además de esto, se está produciendo mucha picaresca entre empresas y comerciantes que, amparados en la mal llamada crisis, aprovechan la situación para hacer resjustes de plantilla (despidiendo trabajadores con condiciones poco menos que ilegales) y dejar pagos pendientes (muchas cantidades pequeñas a varios proveedores y acreedores).

A todo esto hay que unirle el renacer de la economía sumergida, de parados que no llegan a final de mes que tienen que empezar a aceptar trabajos sin contrato y sin dar de alta para poder mantener sus familias.

En mi caso, hace meses que no consigo un cliente y los que tengo han empezado a dejar de pagar las cuotas de mantenimiento por que dicen que no tienen dinero para hacer frente a tanto gasto, esto me esta llevando a plantearme cerrar la oficina, por que no puedo mantenerla, a buscar un trabajo de lo que sea para poder hacer frente a mis obligaciones de pago y muy posiblemente a darme de baja del autonomo y el IAE. En caso de empezar a trabajar en alguna empresa (ya me da igual que sea haciendo programas que limpiando ventanas, puestos a elegir prefiero lo segundo) me voy a ver con el problema de atender las instalaciones que tengo hechas; lo que tambien me plantea si traspasar mi cartera de clientes, vender los fuentes de mi software a quien desee hacerse cargo, y así acabar con la ilusión de mi vida y convertirme en otro más de la cultura del currito, tan extendida en nuestro país.

Me explico; la educación y formación que impartimos en nuestro país se encarga con mucha fuerza de convencer a nuestros hijos de que lo mas importante en la vida es terminar su carrera y conseguir un buen puesto en una empresa o convertirse en funcionario, son pocos los que deciden buscarse la vida por ellos mismos emprendiendo y creando. A eso es lo que llamo “cultura del currito”.

Discupad los retrasos

December 1st, 2008

Hola, en las ultimas semanas estoy basante ocupado con otros temas para poder terminar de pulir los artículos que siguen a los dos anteriores sobre el modelo de datos. Disculpad los retrasos, en cuanto tenga un momento me pongo a ello.

Introducción al modelo de datos (II)

October 19th, 2008

Este es el segundo artículo sobre modelo de datos, en este estudiaremos las clases TFactura y TLineasFactura.

Desde la clase TFactura accederemos a objetos de las clases TCliente y TLineasFactura; y de la clase TLineasFactura accederemos a un objeto de la clase TArticulo.

Observando el código de las clases notaremos que el nivel de automatización al que se llega y que nos facilitará mucho el trabajo de codificación de nuestra aplicación.

CLASS TFactura FROM TQuery

DATA cConsulta

DATA oCli

DATA oLin

METHOD Init( cQuery )

METHOD Delete( nId_Articulo )

METHOD Change( oSender )

ACCESS oCliente

ACCESS oLineas

END CLASS

METHOD Init( cQuery ) CLASS TFactura

DEFAULT cQuery TO “SELECT * FROM cabfac”

::New()

::OnChange := { | oSender | Change( oSender ) }

::cConsulta := cQuery

::Query( ::cConsulta )

RETURN Self

METHOD Delete( nId_Factura ) CLASS TFactura

IF !Empty( nId_Factura )

::Command( “DELETE FROM cabfac “ + ;

“WHERE id = “ + Str( nId_Factura ) + “ “ + ;

“LIMIT 1” )

::Change()

END IF

RETURN Nil

METHOD Change( oSender ) CLASS TFactura

::oCli := NIL

::oLin := NIL

RETURN Nil

METHOD oCliente CLASS TFactura

IF Empty( ::oCli )

::oCli := TCliente():Init( “SELECT * FROM cliente “ + ;

“WHERE id = “ + Str( ::Id_Cliente ) )

END IF

RETURN ::oCli

METHOD oLineas CLASS TFactura

IF Empty( ::oLin )

::oLin := TLineasFactura():Init( “SELECT * FROM detfac “ + ;

“WHERE id_factura = “ + Str( ::Id ) + ” ” + ;

“ORDER BY linea” )

END IF

RETURN ::oLin

//——————————————————————-//

CLASS TLineasFactura FROM TQuery

DATA cConsulta

DATA oArt

METHOD Init( cQuery )

METHOD Delete( nId_Articulo )

METHOD Change( oSender )

ACCESS oArticulo

END CLASS

METHOD Init( cQuery ) CLASS TLineasFactura

DEFAULT cQuery TO “SELECT * FROM detfac”

::New()

::OnChange := { | oSender | Change( oSender ) }

::cConsulta := cQuery

::Query( ::cConsulta )

RETURN Self

METHOD Delete( nId_Factura, nLinea ) CLASS TLineasFactura

IF !Empty( nId_Factura )

::Command( “DELETE FROM derfac “ + ;

“WHERE id_factura = “ + Str( nId_Factura ) + “ “ + ;

“AND linea = ” + Str( nLinea ) + ” ” + ;

“LIMIT 1” )

::Change()

END IF

RETURN Nil

METHOD Change( oSender ) CLASS TLineasFactura

::oArt := NIL

RETURN Nil

METHOD oArticulo CLASS TLineasFactura

IF Empty( ::oArt )

::oArt := TArticulo():Init( “SELECT * FROM articulo “ + ;

“WHERE id = “ + Str( ::Id_Articulo ) )

END IF

RETURN ::oArt

//——————————————————————-//

Para acceder a una factura, símplemente tendremos que escribir el siguiente código:

oFactura := TFactura():Init( “SELECT * FROM cabfac WHERE id = ” + Str( nNumFac )

para acceder a los datos del cliente de una factura:

oCliente := oFactura:oCliente

MsgInfo( oCliente:Nombre )

para acceder a las lineas de la factura:

nTotal := 0

oFactura:oLineas:GoTop()

WHILE !oFactura:oLineas:Eof()

nTotal += oFactura:oLineas:Cantidad * oFactura:oLineas:Precio

oFactura:oLineas:Skip()

END DO

MsgInfo( nTotal )

para acceder al nombre de un artículo:

oFactura:oLineas:oArticulo:Nombre

Con esto terminamos el segundo artículo dedicado a la introducción al modelo de datos. En el próximo estudiaremos como ir mejorando poco a poco las estructuras de datos para, por ejemplo, poder refrescar las consultas, aplicar el uso de vistas, crear métodos que proporcionen totales, etc. Veremos como el modelo básico que hemos definido en estos dos artículos puede completarse hasta conseguir una funcionalidad tan amplia que aumentará el ahorro y claridad posterior de nuestro código.

Introducción al Modelo de Datos (I)

October 17th, 2008

Llevo tiempo pensando en lo útil que resultaría contar con un modelo de datos cómodo que permita facilitar la labor de programación y posterior mantenimiento de nuestras aplicaciones. Coincido con mucha gente que la construcción de un modelo de datos es una tarea pesada que requiere mucha abstracción mental y escribir mucho código, pero también he de admitir que un modelo de datos bien construido ahorra muchas horas de trabajo.

He dividido el artículo en dos para hacerlo menos pesado, aunque al terminar este creo que todos los lectores sabrán por donde van los tiros y que va a pasar en la segunda parte.

Todo el código que pongo aquí está escrito con el único objetivo de ejemplificar un modelo de datos y, desde luego, puede ser mejorado; he suprimido a propósito controles de errores y otras cosas a fin de que se vea claramente como funcionan las clases que lo componen.

El ejemplo que vamos a usar para construir nuestro modelo de datos es una sencilla facturación:

  • Tabla de familias de artículos (id, nombre)
  • Tabla de artículos ( Id, Id_familia, nombre, pvp )
  • Tabla de clientes( Id, nombre, domicilio, telefono )
  • Tabla de cabecera de facturas ( Id, fecha, Id_cliente, iva )
  • Tabla de lineas de facturas ( Id_factura, linea, Id_articulo, cantidad, precio )

Comencemos por identificas las clases que van a constituir nuestro modelo de datos:

  • Clase TFamilia
  • Clase TArticulo
  • Clase TCliente
  • Clase TFactura
  • Clase TLineasFactura

Para el código de los ejemplos usaré xHarbour y Xailer. Todas las clases heredarán de una clase principal y abstracta llamanda TQuery, que es una clase que simula un datasource. La clase TQuery está programada por mí basándome el los wrappers que construyó Manu Expósito en Eagle 1 para acceder de forma nativa a MySQL. Creo que no existen problemas para poder heredar del sistema de datasource de cualquier otro producto. Quien lo desee puede contactarme para que le envíe el código fuente de TQuery.

Las primeras clases que vamos a definir son las relacionadas con las tablas maestras, empezando por las que no contienen referencias a claves foráneas de otras tablas, en nuestro caso, las clases TFamilia y TCliente.

CLASS TFamilia FROM Tquery

DATA cConsulta

METHOD Init( cQuery )

METHOD Delete( nId_Familia )

END CLASS

METHOD Init( cQuery ) CLASS TFamilia

DEFAULT cQuery TO “SELECT * FROM famila”

::New()

::cConsulta := cQuery

::Query( ::cConsulta )

RETURN Self

METHOD Delete( nId_Familia ) CLASS TFamilia

IF !Empty( nId_Familia )

::Command( “DELETE FROM familia “ + ;

“WHERE id = “ + Str( nId_Familia ) + “ “ + ;

“LIMIT 1” )

END IF

RETURN Nil

//——————————————————————//

CLASS TCliente FROM Tquery

DATA cConsulta

METHOD Init( cQuery )

METHOD Delete( nId_Cliente )

END CLASS

METHOD Init( cQuery ) CLASS TCliente

DEFAULT cQuery TO “SELECT * FROM cliente”

::New()

::cConsulta := cQuery

::Query( ::cConsulta )

RETURN Self

METHOD Delete( nId_Cliente ) CLASS TCliente

IF !Empty( nId_Cliente)

::Command( “DELETE FROM cliente “ + ;

“WHERE id = “ + Str( nId_Cliente ) + “ “ + ;

“LIMIT 1” )

END IF

RETURN Nil

//——————————————————————//

Constituiremos ahora la clase para controlar la tabla de artículos, que como podemos observar, contiene una clave foránea a la tabla de familias (Id_familia); por lo tanto, desde nuestro modelo de datos, un objeto oArtículo de la clase TArtículo tendrá que poder acceder a los datos de la familia de cada artículo, facilitando posteriormente las labores de programación de nuestra aplicación.

CLASS TArticulo FROM TQuery

DATA cConsulta

DATA oFam

METHOD Init( cQuery )

METHOD Delete( nId_Articulo )

METHOD Change( oSender )

ACCESS oFamilia

END CLASS

METHOD Init( cQuery ) CLASS TArticulo

DEFAULT cQuery TO “SELECT * FROM articulo”

::New()

::OnChange := { | oSender | Change( oSender ) }

::cConsulta := cQuery

::Query( ::cConsulta )

RETURN Self

METHOD Delete( nId_Articulo ) CLASS TArticulo

IF !Empty( nId_Articulo)

::Command( “DELETE FROM articulo “ + ;

“WHERE id = “ + Str( nId_Articulo ) + “ “ + ;

“LIMIT 1” )

::Change()

END IF

RETURN Nil

METHOD Change( oSender ) CLASS TArticulo

::oFam := NIL

RETURN Nil

METHOD oFamilia CLASS TArticulo

IF Empty( ::oFam )

::oFam := Tfamilia():Init( “SELECT * FROM familia “ + ;

“WHERE id = “ + Str( ::Id_Familia ) )

END IF

RETURN ::oFam

Vamos a detenernos un instante a estudiar que tienen estas clases dentro. De forma general, todas las clases llevan una DATA que contiene la consulta efectuada (cConsulta) y los MÉTODOS Init() y Delete().

El método Init() es el encargado de construir y retornar el objeto correspondiente. En su interior nos encontramos instrucciones que, a parte de establecer un valor por defecto para la consulta, también realizan:

  1. Llamar al método New() de la superclase para la construcción del objeto.

  2. Llamar al método Query() de la superclase para ejecutar la consulta y cargar los datos correspondientes.

El método Delete() es el encargado de eliminar una fila de la tabla correspondiente. En caso de usar bases de datos SQL recomiendo tener bien definida la integridad referencial. En otro tipo de almacenes de datos, en este método habrá que incluir el código necesario para eliminar información de las tablas que contengan información de la fila que estamos eliminando.

Estudiando la clase TArticulo podemos observar algunas diferencias muy significativas: aparece una DATA aFam, el método Change() y el método especial ACCESS oFamilia.

Mediante la palabra reservasa ACCESS de xHarbour se define un método especial que se comportará como una DATA y que además ejecuta su código cada vez que se instancia.

La DATA oFam contendrá un objeto de la clase TFamilia descrita anteriormente.

El método Change() se ejecutará cada vez que dispare el evento OnChange() de la clase TQuery. Este evento responde cada vez que se produce un cambio al añadir, actualizar, borrar, navegar o recargar datos de la consulta. Este método pone a NIL la data oFam para controlar un tipo de recursividad que veremos más adelante.

El método ACCESS oFamilia se ejecutará cada vez que accedamos a él, ejecutando la consulta que carga los datos de la familia relacionada con el artículo actual. Para evitar la recursividad y que se ejecuten consultas constantes (perdida de velocidad :-(), miramos si está vacío.

Con lo visto hasta este momento creo que ya habréis podido adivinar que el modelo de datos perimite acceder de forma automática a los datos de tablas relacionadas sin necesidad de escribir código adicional. Comparemos:

  1. Forma tradicional sin modelo de datos:

oArticulo := TQuery():New( “SELECT * FROM articulo” )

WHILE !oArticulo:Eof()

oFamilia := Tquery():New( “SELECT * FROM familia “ + ;

“WHERE id = “ + Str( oArticulo:Id_Familia ) )

MsgInfo( oFamilia:Nombre )

oArticulo:Skip()

END DO

  1. Usando el modelo de datos:

oArticulo := TArticulo():New( “SELECT * FROM articulo” )

WHILE !oArticulo:Eof()

MsgInfo( oArticulo:oFamilia:Nombre )

oArticulo:Skip()

END DO

Es obvio que usando un modelo de datos conseguimos claridad y automatización en la mayoría de los procesos que tenemos que realizar dentro de nuestros programas.

En la segunda parte de este artículo veremos como se automatiza la clase Tfactura.