«¡¡ GRACIAS !!» xD
martes 3 de noviembre de 2009
Tono, Sony, Cheché y yo
«¡¡ GRACIAS !!» xD
sábado 24 de octubre de 2009
Ser o no ser
Como saben, el operador Is tiene como propósito permitirnos averiguar si una referencia de objeto apunta o no a una instancia de cierta clase o de clase descendiente de ésta. Como ejemplo, usamos el operador en este pequeño procedimiento llamado SetText, cuya finalidad hipotética es establecer el texto de un componente dado de forma genérica:
Procedure SetText (Const C :TComponent; Const Text :String);
Begin
If C Is TButton Then
TButton (C).Caption := Text
Else
If C Is TEdit Then
TEdit (C).Text := Text
Else
// Otras clases de componentes
End;
El parámetro C es declarado de tipo TComponent para que el polimorfismo permita que se proporcione cualquier objeto de clase descendiente de TComponent. El primer If resultará verdadero si el componente dado es un TButton (o de clase descendiente de TButton). El segundo If resultará verdadero si C es de clase TEdit o descendiente.
Podemos entonces llamar al procedimiento SetText de esta forma:
SetText (Button1, 'Hola');
SetText (Edit1, 'a todos');
Por favor, no ahondemos en la finalidad de ese procedimiento y su implementación, es sólo un ejemplo de introducción al tema que quiero plantear. Tampoco pretendo hacer una exposición académica sobre el uso tradicional del operador Is, pues de eso hay ya mucho material publicado. Quiero enfocarme en un detalle curioso y poco documentado que convendría tomarse muy en cuenta.
Consideremos el siguiente formulario (admito que hasta hace un par de años les llamaba formas), en el que tenemos un componente TButton y un componente TEdit:
Hace tiempo, trabajando en no sé qué cosa, necesitaba obtener un componente por su nombre, conociendo de antemano que el componente en cuestión era de una clase específica. Sabemos que el método FindComponent sirve para obtener un componente por su nombre, y siempre devuelve éste como expresión de tipo TComponent, lo cual está muy bien.
Declaración del método TComponent.FindComponent:
function FindComponent(const AName: string): TComponent;
Pero conociendo no sólo el nombre, sino también la clase del componente que yo deseaba obtener, TButton, para fines de este ejemplo, me resultaba muy útil contar con una rutina que actuara como FindComponent, pero que, en lugar de regresar el objeto como TComponent, lo devolviese como TButton (así evitaría escribir un molde de tipo cada vez que obtuviera un TButton por su nombre). Por tal razón creé una rutina parecida a este método función:
Function TForm1.Boton (Const Nombre :String) :TButton;
Var
C :TComponent;
Begin
C := FindComponent (Nombre);
If C Is TButton Then
Result := TButton (C)
Else
Result := Nil;
End;
Hasta ahí todo estaba en armonía con el cosmos, hasta que mi espíritu perfeccionista me dijo al oído «ahórrate la variable C». Decidí entonces cambiar un poco el código, en principio para experimentar:
Function TForm1.Boton (Const Nombre :String) :TButton;
Begin
Result := TButton (FindComponent (Nombre));
If Result Is TButton Then
Exit
Else
Result := Nil;
End;
En esta segunda versión de la rutina utilizo Result directamente, en lugar de la variable local C que ha sido desechada. El molde de tipo TButton en la llamada a FindComponent es necesario por obvias razones: el compilador no permitiría asignar una expresión TComponent a una variable cuyo tipo declarativo no fuese esa clase o alguno de sus ancestros (el tipo declarativo de Result es TButton, clase que no es ancestro, sino descendiente, de TComponent).
A simple vista podría parecer aceptable esta forma de simplificar el código, pero surge una puntual interrogante, ¿cómo evalúa Delphi la expresión Result Is TButton? es decir:
¿El operador Is trabaja todo el tiempo con la clase real de la instancia proporcionada o también considera el tipo declarativo de esa expresión objeto?
La respuesta a dicha pregunta puede ser respondida poniendo a prueba la nueva versión del método Boton, con el siguiente código:
procedure TForm1.FormShow(Sender: TObject);
Var
B :TButton;
begin
B := Boton ('Edit1');
If B <> Nil Then
ShowMessage ('Encontramos el botón ' + B.Name + '.');
end;
Cuando el formulario se abra, observarán en pantalla un bonito, revelador y algo desalentador mensaje como este:
Hagamos otro pequeño cambio al método Boton:
Function TForm1.Boton (Const Nombre :String) :TButton;
Begin
Result := TButton (FindComponent (Nombre));
If Result Is TButtonControl Then
Exit
Else
Result := Nil;
End;
En lugar de TButton, he puesto su clase padre (TButtonControl) a la derecha de Is, y el resultado de la prueba fue el mismo. Esto me permite elaborar algunas conclusiones de cómo trabaja realmente el operador Is:
La ayuda de Delphi dice que Is verifica la clase real que en tiempo de ejecución tiene la instancia evaluada. Pero con las pruebas anteriores hemos descubierto que este operador considera en primer lugar el tipo de dato con el que fue declarada la expresión objeto que se evalúa. Si el tipo de dato declarativo de la expresión, a la izquierda del operador Is, es la clase indicada a la derecha de éste o una descendiente, el operador devuelve True en automático sin revisar ya la clase real de objeto. Así pues, la clase real del objeto es revisada solamente en los casos donde la expresión del lado izquierdo indica (por su declaración) una clase ancestro de la especificada en el lado derecho.
Lo anterior hace que este par de Ifs se cumplan, y sin que ocurra error alguno en el segundo:
procedure TForm1.Button1Click(Sender: TObject);
begin
If TForm (Button1) Is TCustomForm Then
ShowMessage ('!');
If TComponent (5) Is TComponent Then
ShowMessage ('!');
end;
Debo decir que este funcionamiento del operador Is me parece muy razonable, pues es poco visto que una expresión regrese un valor que no sea compatible con su tipo declarativo. De hecho, en la mayoría de los casos, eso es totalmente desaconsejable. El hecho de que Is no siempre verifique la clase real del objeto dado contribuye con toda seguridad a una ejecución más rápida de la operación.
Entonces, para ahorrarnos la variable C en el método Boton, haría falta un pequeño ajuste:
Function TForm1.Boton (Const Nombre :String) :TButton;
Begin
Result := TButton (FindComponent (Nombre));
If TComponent (Result) Is TButton Then
Exit
Else
Result := Nil;
End;
Podemos recurrir a los métodos ClassType o InheritsFrom, en lugar del operador Is. Pero también podemos declarar la variable C con la directiva Absolute, para que ocupe el mismo espacio de memoria que Result (uno de mis trucos favoritos):
Function TForm1.Boton (Const Nombre :String) :TButton;
Var
C :TComponent Absolute Result;
Begin
C := FindComponent (Nombre);
If C Is TButton Then
Exit
Else
Result := Nil;
End;
Lo importante es tener presente que el operador Is toma en cuenta el tipo declarativo del objeto evaluado y no siempre revisa la clase de esa instancia.
Un verdadero abrazo.
Al González.
sábado 26 de septiembre de 2009
Cinco años exprés
A este estimado programador PHP, altamente orientado a herramientas libres (pero no siendo uno de esos fundamentalistas que ubican su Meca en la Antártida) le di un curso de POO en Delphi hace cinco años, adquiriendo bases con las cuales ahora ha creado su primer objeto derivado en un lenguaje que sí tiene intenciones de utilizar.
Colega dice:
hola hola mi estimado, cómo has estado, ya tiene un buen que no te conectabas
Al González dice:
¡Hola! Muy bien, gracias, ¿y tú?
Colega dice:
igual bien bien, sigues en Morelia?
Al González dice:
Así es, ¿y tú?
Colega dice:
si, aqui en Chetumal, trabajando y aprendiendo
Al González dice:
Que bien, ¿con qué estás ahora?
Colega dice:
estamos concluyendo y dándole mantenimiento al sistema de control escolar de ahi donde trabajo, y en proyectos extras estoy en espera que me den luz verde para comenzar con un sistema de almacén
y tu que onda?? en qué andas trabajando?
Al González dice:
[...] y dando asesorías sobre DataSnap y DBX
Colega dice:
qué son DataSnap y DBX?
Al González dice:
Tecnologías de Delphi para aplicaciones multicapa
Colega dice:
[...]
Al González dice:
[...]
Colega dice:
si, ya he escuchado eso, incluso si autorizan el sistema de almacén y según lo que logre analizar ya más detenidamente, usaré ASP.NET MVC
Al González dice:
Vaya, por fin vas a usar algo distinto a lo tradicional del mundo Open Source
¿Con qué lenguaje lo manejarás?
Colega dice:
de hecho ya he estado trabajando con .NET, usando Windows Forms
y trabajo con C#
e incluso cree mi primer objeto derivado e hice uso de la sobreescritura de métodos, y agregué nuevas propiedades que se ven en el inspector de objetos
jejejeje mis primeros pininos, aún me falta, y mucho de donde aprender
[...]
Al González dice:
[...]
¿Y cuánto invertiste en licencias?
Colega dice:
nada, estoy trabajando con las versiones exprés de los editores, tanto de C#, como de ASP.NET y también de SQL Server Express, de igual manera el amigo con el que estoy trabajando tiene licencias gratis por 3 años debido a que dio de alta su empresa en el sitio de Microsoft y puede descargar los productos sin problema alguno
Ya me voy Al, fue un gusto platicar contigo, nos vemos, cuídate y espero verte pronto de nuevo para seguir charlando sobre programación
Al González dice:
Hasta pronto, muy buen día.
Cualquier parecido con la realidad es cruda coincidencia. :)
Un abrazo testimonial.
Al González.
miércoles 23 de septiembre de 2009
Guanajuato, otra Nueva Inglaterra del siglo XVII
De entrada la frase está incompleta, pues pareciera que a alguien le ganó el pudor cuando debía añadir “para empezar a disfrutar del sexo en pareja” (y ya ni hablemos de sexo grupal, porque vivo muy cerca de la capital de ese estado y podrían venir por mí para quemarme en leña verde).
¡Pero caramba! La Secretaría de Educación de Guanajuato no sólo condena a miles de jóvenes a evitar el pleno disfrute de su sexualidad durante muchos de los mejores años de su vida (considerando que ya nadie en su sano juicio se casa antes de cumplir 28), y con todas las consecuencias sicológicas negativas que la abstinencia sexual conlleva, sino que encima de todo miente a sus futuros ciudadanos diciéndoles que, como por arte de magia, el organismo humano adquiere infalibles anticuerpos contra el VIH y otras enfermedades venéreas en cuanto se firma un acta matrimonial. ¡Qué estupidez!
Ya veo las oficinas del registro civil de León atestadas de adolescentes inquietos y sudorosos, con la mochila escolar en la espalda y mandando mensajes escritos a la velocidad del rayo, en espera del juez que habrá de unirlos de dos en dos, cual Noe funcionario. Casarse para tener sexo cien por cien seguro, ¡qué gran idea! Yo mañana mismo me registro, ¡por fin sabré lo que es hacerlo sin condón!
No cabe duda que mientras la mayor parte de la gente de este planeta intenta progresar de algún modo, ciertas mentes pequeñitas pero con poder político buscan hacer realidad el infierno de Hester Prynne.
Ojalá destituyan a los funcionarios responsables de atrocidades como esta, pues necesitan ser educados antes de injerir en el destino de una sociedad.
Un abrazo sexual.
Al González.
sábado 12 de septiembre de 2009
Cierre de Programadores Delphi de México
Como muchos saben, en el año 2008 Microsoft cerró el servicio de MSN Groups, lugar donde se encontraban alojados inicialmente los registros de la comunidad Web Programadores Delphi de México (PDM). Ya para entonces el sitio contaba con más de 3 mil colegas inscritos y un acervo considerable de mensajes con información técnica. Había cumplido con su misión de acercar entre sí a una cantidad importante de desarrolladores Delphi de la República Mexicana y otros países de habla hispana.
En un mundo global, donde la única frontera vigente es el idioma, otro sitio Web de mejor formato y mayor trayectoria y riqueza informativa empezó a cumplir el mismo propósito para los desarrolladores Delphi de México y países vecinos. Alrededor del año 2004 Club Delphi dejaba de ser visto por los desarrolladores americanos como “un foro de España”, para convertirse en una comunidad verdaderamente plural, en la cual ahora es fácil encontrar personas de cualquier país de Iberoamérica.
Para PDM, que nunca tuvo el objetivo de competir contra otras comunidades Web, sino llenar espacios que estaban vacíos para los desarrolladores mexicanos, dejó de tener sentido su operación desde que tales desarrolladores comenzamos (porque me incluyo) a encontrar comodidad, trascendencia, respuestas, crecimiento y satisfacción en el otro foro. Así que el cierre de PDM quedaba anunciado implícitamente en su propia naturaleza.
Personas cercanas a mí me sugirieron añadir al sitio el ingrediente de la competencia, mantenerlo en pie, mejorarlo y ofrecer características que atrajeran la preferencia de un mayor número de participantes. Mi opinión fue que como iban las cosas con Delphi (mal), lo mejor era contribuir a tener una sólida y única comunidad Web de programadores Delphi de habla castellana. Y qué mejor que Club Delphi para ser esa comunidad.
Pero se atravesó una serie de sucesos desafortunados que parecen haber sido orquestados por una mente perversa, y el sueño de tener una gran, única e incluyente comunidad Web que ejerciera mayor presión sobre el fabricante de Delphi y tomara participación considerable en su destino como herramienta de programación, se esfumó cuando varios miembros destacados del prestigioso club se vieron orillados a abandonarlo y crearon legítimamente un espacio alternativo. Aquello sucedió de tal manera que resultó imposible emitir un juicio contundentemente a favor de alguna de las partes en conflicto, pues todo mundo tenía razón y todo mundo estaba equivocado. Si fuera yo un conspiracionista, de esos que creen en el falso precepto de “piensa mal y acertarás” (la verdad es que casi siempre se yerra), diría que alguien poderoso estaba interesado en provocar la separación ocurrida pero con la menor pérdida de credibilidad posible para ambas partes. Sí, suena como si alguien hubiese querido abrir el mercado sin que ninguno de los protagonistas se diera cuenta del plan (una locura conspiracionista, no hagan mucho caso a esta parte :p).
El hecho palpable es que hay un nuevo foro para los miles de desarrolladores Delphi que hablan español, y sus dirigentes llevan consigo una tremenda carga de motivación y energía que seguramente trascenderá a su primer año de vida, pues éste está por cumplirse ya. Sus estadísticas son relevantes, y aunque por ahora la mayoría de los mensajes publicados son de esparcimiento, existe una clara tendencia de crecimiento en las aportaciones técnicas, además de que se promueven diversos tipos de actividades más allá de los tableros de mensajes. DelphiAccess, es pues, una comunidad prometedora.
Con el cierre oficial de PDM (en la práctica ha ido ocurriendo a la velocidad en que muere una planta de maíz después de ser cosechada), sus administradores, Alejandro Ontiveros, Fabián Durón y un servidor, recomendamos a todos los desarrolladores Delphi de habla castellana registrarse y participar en las dos comunidades Web más importantes para la programación en Delphi de nuestra región idiomática:
Club Delphi, poseedora de un invaluable acervo técnico y cultural, casa de decenas de desarrolladores que merecen una estatua y sitio con gran infraestructura subyacente.
DelphiAccess, el foro que asemeja a las 13 Colonias americanas en su espíritu por encontrar justicia y libertad.
Muchas gracias a todos los miembros de PDM por estos siete años de increíble aventura.
Un abrazo mexicano.
Al González. :)
viernes 28 de agosto de 2009
El evento OnTwentyTen
El día martes 1 será la primera presentación en la Cámara Nacional de Comercio de Guadalajara y el jueves 3 en el Centro Asturiano Polanco de Ciudad de México. Su servidor irá desde Morelia a ésta última, a diferencia del año anterior, cuando pude asistir a la presentación de Delphi 2009 en Guadalajara.
Se nota que esta versión 2010 lleva buena hechura y es muy posible que la incluya en mi lista de versiones más recomendables, junto con Delphi 7 y 2007.
Consecutivamente y para fines de soporte técnico es la versión 13 de Delphi, un número cabalístico entre millones de estadounidenses, pero de significado positivo entre los programadores de todo el mundo. Pues 13 es el valor ASCII de la tecla de computadora más emblemática, y por si fuera poco en hexadecimal se escribe con una enorme y regia letra...
D
Si tienen oportunidad no dejen de asistir a alguna de las dos presentaciones. Y si son clientes de Gopac o Embarcadero que viven en grandes ciudades olvidadas como Chihuahua, Monterrey, Culiacán, Torreón, Veracruz, Cancún, Mérida, Tuxtla, Acapulco, Tampico, Chilpancingo, Campeche, León, Pachuca, Reynosa, Hermosillo, etc. (u otras todavía más olvidadas como Parral o Huauchinango), llámenles para que miren a verlos y pronto se logre materializar uno de estos eventos en su localidad.
Un abrazo hacia la grandeza de Delphi en México.
Al González. :)
P.D. Además D en números romanos es 500, el precio en dólares que tarde o temprano habrá de tener la edición Professional del paquete para por fin ser altamente competitiva esa edición en el mercado. Claro, siempre y cuando se incluya el controlador de Firebird en ella. ;)
viernes 14 de agosto de 2009
Visita de descanso
Lo de descansar es parcialmente cierto, puesto que aprovecharé algunos ratos libres para seguir avanzando en mi actual proyecto. Pero si alguno de los colegas de la zona quiere acercarse a tomar una cerveza o café conmigo, es bienvenido de hacerlo. Me dará gusto charlar con otros seres humanos, digo, con otros programadores.
Estaré por la zona de Insurgentes y Reforma.
Al González. :)
sábado 8 de agosto de 2009
Descubren ciudad perdida
Consta de cinco laboratorios, áreas de hospedaje, cascada artificial, aeropista, tres plantas de luz, sistema de drenaje y agua potable.
Sus operarios y ocupantes tenían catálogos de prostitutas con tarifas de hasta 22 mil dólares, y también disponían de 10 antenas de Sky [televisión de paga satelital], tres de red satelital, 18 vehículos, entre camionetas y cruatrimotos, y dos retroexcavadoras (una, de las llamadas mano de chango).
Entre los edificios de complejo hay bodegas, lavanderías, cocina y enfermería. También se hallaron 164 tambos [bidones] de 200 litros, todos llenos de acetona, tolueno, sosa cáustica y otros precursores químicos; tanques de gas y oxígeno, así como de 10 toneladas de marihuana, 20 kilos de cocaína pura, 12 armas largas, 500 cartuchos, 20 mil dólares en efectivo y equipo de radiocomunicación.
Considerada por militares como la más grande fábrica de drogas sintéticas hallada en el país, Ciudad Crystal fue descubierta en el transcurso de la semana, durante un operativo conjunto de las zonas militares novena y décima.
Desde el aire no se distinguía gracias a su camuflaje de hojarasca en techos y paredes. Más de cerca se notaba su silueta arquitectónica, pero fue necesario volar en helicóptero hasta la comunidad de Las Trancas, y de ahí subir a la alta Sierra Madre Occidental para llegar al sitio.
Personal militar calculó que en el complejo trabajaban unas 120 personas entre vigilantes, laboratoristas, cocineros y personal de enfermería; pero no hubo detenidos pues cuando el Ejército se acercaba todos pudieron escapar.
Habitantes de comunidades cercanas dijeron al Ejército que en las cabañas rodeadas de casas de seguridad y laboratorios vivían capos de alto rango como Joaquín El Chapo Guzmán, Ismael El Mayo Zambada e Ignacio Nacho Coronel.
Fuente.
miércoles 15 de julio de 2009
Pascal en .NET
Los pasos de Microsoft eran demasiado grandes para llevarles el ritmo al tiempo de tratar de conservar en Delphi su tradicional compatibilidad hacia atrás, además de su compatibilidad en paralelo con la emblemática API Win32, conjunto de DLLs que en su momento Microsoft incluyó de forma bastante generosa en todas las versiones de Windows para facilitar a otros la creación de aplicaciones.
.NET es la “nueva API de Windows”, con un par de grandes diferencias. Más que una API, es un conjunto de varias tecnologías mucho más avanzadas y orientadas a objetos que la API Win32. La otra gran diferencia es escabrosa: Microsoft decidió crearla al mismo tiempo que decidió pelear por ser también un fabricante competitivo de lenguajes, con el surgimiento de las primeras versiones de sus C# y Visual Basic .NET. Imaginen a un arquitecto obeso que diseña la más moderna alberca pública del mundo, y el día de la inauguración es el primero en meterse a ella, ¡pero arrojándose de panza desde la plataforma de 10 metros! Salpicando a todo el mundo a su alrededor y regodeándose mientras nada, sin mirar dónde patalea.
Entre el afán de CodeGear de mantener compatibilidad hasta con el color de ojos de Gonzalo Guerrero (el conquistador español que fue convertido en guerrero y noble maya), y el afán de Microsoft de convertirse en un verdadero fabricante de lenguajes, el espíritu prudente de Delphi no tenía mucho espacio para respirar. Así que, aunque algo tarde, en California decidieron tomar medidas extremas y por primera vez aceptaron que no podrían ser los mejores, encargando a la pequeña empresa RemObjects una versión especial de su ya famoso entorno Object Pascal, Oxygen, la cual fue bautizada como Delphi Prism.
Al gordo ya se le pasó la euforia y empieza a tener problemas serios con otras de sus tecnologías (Windows, Office, Entity Framework, LINQ...). Sin embargo, la alberca .NET ha quedado bastante bien como para dar servicio a miles de bañistas (cabe mencionar que un ingeniero ex-Borland estuvo detrás de los trabajos y es el verdadero arquitecto de muchas de sus características).
Así las cosas, con una plataforma .NET estable y rica y este nuevo Delphi Prism nada titubeante en comparación con los Delphi .NET anteriores, lo único que hacía falta era un buen libro para aprender a conocer esta nueva herramienta. ¡Ah! pero tenía que ser un libro que sirviera a todos aquellos que no habíamos querido tocar las aguas de .NET ni con los dedos del pie por falta de certidumbre en la época del CodeGear solitario, y quizá también por miedo a lo desconocido y el romanticismo cultural que guardamos entorno a la popular API Win32. Un libro que además de explicarnos paso a paso el uso de Delphi Prism, también nos explicara qué rayos es .NET y con qué cubiertos se come.
Este es un libro escrito en español por un desarrollador mexicano con gran experiencia en Delphi. No tuvo que exiliarse o hacer muchos viajes al extranjero para darse a conocer. Marco Antonio Santin ha escrito su ópera prima desde el lugar donde ha vivido gran parte de su vida, la pequeña ciudad de Zitácuaro, Michoacán. Es de los que ven a México como lo que es, un país hermoso lleno de oportunidades de éxito. Éxitos como este:

http://markdelphi.intelsoftassociates.com/
Muchas felicidades, Marco.
Al González. :)
domingo 28 de junio de 2009
DTE y la figura del bibliotecario
He decidido rescatar un par de artículos que publiqué hace varios años en Club Delphi y Programadores Delphi de México, y unirlos en uno solo, dada la relación tan estrecha que guardan entre sí y la importancia que considero podría tener este material en el mundo del desarrollo de software.
La Distribución del Trabajo por Especialidades es un paradigma de organización laboral aplicable a todas las profesiones que alcanzan cierto nivel de complejidad. Consiste en clasificar todas las tareas involucradas en un ámbito laboral por tipo de actividad o, más formalmente, por especialidades, y respetando esa clasificación durante los procesos de estimación, repartición y ejecución del trabajo. La idea fundamental de la DTE es tener claramente identificadas las diferentes áreas de una profesión y promover el surgimiento de especialistas y el trabajo en equipo, para lograr resultados de mayor calidad, dignificar la labor de los profesionistas y elevar su nivel de vida. Por dar un ejemplo donde la DTE ha tenido éxito, podemos mencionar la profesión médica, la cual lleva muchos años fomentando la especialización con resultados realmente admirables.
Debemos aceptar el hecho de que, en cualquier profesión, la especialización siempre será una ventaja competitiva tanto para los trabajadores como para las empresas que los emplean. El resultado directo de la especialización es un mejor desempeño y una mayor calidad en los productos y servicios obtenidos. Una persona especializada tiende a realizar mejor su trabajo que una no especializada. Al unir los esfuerzos de diferentes especialistas en un mismo equipo de trabajo, logramos un entorno de alta productividad.
Quizá el lector empresario se plantea en este momento el siguiente cuestionamiento: «De acuerdo, lo ideal sería que mi empresa contara con varios especialistas, pero sería imposible sostener esa nómina. La cantidad de trabajo y los ingresos por ventas son insuficientes».
Ese es un punto de vista típico del empresariado del siglo XX. En la mayoría de los casos, esa perspectiva derrotista pierde validez y se vuelve anacrónica cuando en contraparte se exponen estos sólidos argumentos del siglo XXI:
- Un especialista no necesariamente debe percibir un salario mucho mayor que el de un trabajador no especializado, aunque es deseable y económicamente sano que si tenga un nivel de ingresos superior. Un especialista es un profesional, y por lo tanto entiende que el valor económico de su trabajo está determinado por el mercado; siempre habrá un punto de equilibrio aceptable entre lo que las empresas quieran pagarle al especialista y lo que éste quiera cobrar.
- Un trabajador puede cubrir dos o más especialidades. La especialización no significa que la empresa deba contar forzosamente con un trabajador por cada especialidad. La meta laboral es cubrir todas las especialidades, independientemente de cuántas personas se ocupen para ello. Lo importante es que cada especialidad esté cubierta por alguien que desempeñé eficazmente su labor en esa área. Hay muchos profesionales que destacan en más de una.
- La empresa puede recurrir a la contratación de servicios externos (outsourcing) y al pago por hora, dos prácticas altamente efectivas y cada vez más difundidas alrededor del mundo. Una excelente forma de contar con el trabajo de diversos especialistas es contratando los servicios de profesionales independientes o de compañías consultoras, además de instaurar el pago por hora en lugar de abultados sueldos que, en muchos casos, no equivalen a la cantidad real de tiempo efectivo trabajado. De esta manera, la empresa decide cuándo, a quién, por cuánto tiempo y para qué actividades contratar a cada especialista. Por su parte, los especialistas gozan de una mayor autonomía laboral, permitiéndose cotizar sus servicios en el mercado con toda libertad.
- Cuando una empresa desarrolla sus actividades más importantes empleando a especialistas, lógicamente incrementa sus ingresos por ventas. Esto es porque al mejorar la calidad de sus productos y servicios —gracias a la especialización— eleva su competitividad, logra una mayor aceptación de los mismos en el mercado y, opcionalmente, puede cotizarlos a un precio más alto.
Evidentemente, cada profesión tiene sus rampas y sus muros que facilitan u obstaculizan la especialización. Y cada una requiere un tratamiento específico para establecer una logística DTE efectiva. El autor de este artículo es un desarrollador de software, especialista en programación de bibliotecas, a quien le interesa la puesta en práctica de un modelo DTE en las empresas de software y en las oficinas de los programadores independientes. Tanto él como otros colegas de diversas especialidades están convencidos de que la DTE dará grandes beneficios tanto a los profesionistas y empresas creadores de software como a los usuarios de tecnologías de información, empezando por una mayor calidad de los productos y servicios proporcionados y propiciando que los desarrolladores —usualmente llamados informáticos—, convivan en un entorno laboral más digno, respetado, satisfactorio y estable.
Clasificación de las especialidades
Cuando se pretende establecer un modelo DTE, lo primero es determinar cuál o cuáles son las clasificaciones más efectivas. En ocasiones leemos o escuchamos sobre desarrolladores especialistas en el manejo de herramientas o entornos de software específicos, como base de datos Oracle™, lenguaje Delphi™, programación Web, y muchísimos otros. Eso nos muestra que, de facto, ya existe una serie de especialidades que puede ser aprovechada al aplicar la DTE. Sin embargo, creo que la clasificación de especialidades por herramientas o entornos de software obedece más al gusto personal que a las habilidades reales del profesionista.
Supongamos que tenemos a un autodenominado experto en Java, un fanático del lenguaje que no programa nada si no es con algún entorno Java. Éste realiza un trabajo excelente programando rutinas de eventos, validando la lógica de negocios y creando clases de objetos para las aplicaciones que desarrolla, pero sus sentencias SQL de acceso a datos no son del todo óptimas y su diseño de interfaces de usuario carece de estilo gráfico y calidad gramatical. Entonces inferimos que realmente no se trata de un experto, más bien es un desarrollador que conoce el lenguaje lo suficiente como para crear aplicaciones funcionales y hasta cierto punto aceptables; se le reconocen importantes habilidades de programador operativo, de lógica de negocios y de bibliotecas, pero tiene escasa destreza en las áreas de administración de datos y diseño visual. Si una empresa le asigna cualquier actividad que tenga que ver con programación en Java, muchas de esas actividades serán mal ejecutadas (las que no son de su dominio).
El ejemplo anterior es tan claro como lamentablemente típico. La especialización a partir de herramientas o entornos de software por lo general termina siendo una especialización a medias, poco eficiente. Como promotor de la DTE creo que la clasificación de especialidades debe originarse en función de los diferentes tipos de labores, lo cual va más acorde con las habilidades reales de los desarrolladores y no tanto con sus gustos personales. Naturalmente, pienso que es válido crear subespecialidades por herramientas, entornos u otras clasificaciones que satisfagan el gusto personal de cada desarrollador, pero siempre partiendo de especialidades mayores clasificadas por tipo de actividad. Bajo esta tónica, la empresa del ejemplo anterior le encargará a nuestro reconocido especialista en programación operativa, de lógica de negocios y de bibliotecas en Java las tareas que son de su competencia profesional, mientras que el diseño de las interfaces de usuario y la construcción de sentencias SQL serán asignados al especialista respectivo.
Si el lector empresario está pensando de nuevo en la “imposibilidad” de contratar a «tantos» desarrolladores especialistas, le sugiero, de la manera más atenta, que vuelva a leer los cuatro sólidos argumentos del siglo XXI que expuse casi al comienzo de este artículo.
Principales especialidades
Algunos colegas y yo hemos detectado doce principales especialidades y cinco subespecialidades, en función de los diferentes tipos de tareas realizadas al desarrollar sistemas de software. A cada una le hemos asignado un acrónimo de dos letras mayúsculas para fines de simplificación. Se listan en seguida:
- Análisis (AN)
- Dirección (DI)
- Administración de datos (AD)
- Modelado de datos (MD)
- Administración de bases de datos (AB) - Diseño visual (DV)
- Diseño gráfico (DG)
- Diseño operativo (DO)
- Reporteo (RE) - Programación operativa (PO)
- Programación de lógica de negocios (LN)
- Programación de bibliotecas (PB)
- Preparación de instaladores (PI)
- Documentación (DC)
- Control de calidad (CC)
- Instrucción (IN)
- Soporte técnico (ST)
Concientes de que no es muy viable ni estratégico para la mayoría de las empresas de software contratar a doce o más especialistas de tiempo completo, pero a la vez convencidos de las ventajas de una organización DTE, los promotores del modelo consideramos que deben aceptarse dos escenarios perfectamente combinables:
- Cada uno de los desarrolladores en una empresa estará a cargo de la realización de tareas de una o más especialidades. El equipo de desarrolladores (que en algunos casos podrá ser de uno sólo) deberá identificar y tratar de cubrir todas las especialidades mayores propuestas en este modelo. La repartición de las tareas se hará en función de las especialidades y disponibilidad de tiempo —en ese orden— de cada desarrollador. Siempre toda tarea deberá estar enmarcada en alguna de las especialidades, desde el análisis hasta la implantación.
- La empresa recurrirá a la contratación de especialistas DTE externos cuando lo considere estratégico. Esto puede suceder cuando la empresa no cuente con el especialista interno adecuado o cuando éste no disponga de tiempo por estar ejecutando otras actividades que le fueron asignadas previamente. El servicio de outsourcing contratado podrá ser ejecutado de forma presencial en las instalaciones de la empresa, o a distancia, con las facilidades que Internet ofrece para ello.
Pero esta Red Colaborativa tiene bondades adicionales. Al instaurarse el modelo DTE en las oficinas de los desarrolladores independientes y en las pequeñas empresas de software, pueden crearse magníficos equipos de teletrabajo para desarrollar proyectos de sistemas de cualquier tamaño y para cualquier compañía u organización. Con el modelo DTE y la Red Colaborativa, todos los desarrolladores independientes y pequeñas empresas de software tendrán la capacidad de competir en el mercado, ofreciendo software de alta calidad y a la medida de cualquier empresa o institución. Así por ejemplo, un programador serio y formal que trabaja desde casa podrá fabricar una completa solución de software para una compañía local, echando mano de especialistas externos DTE de cualquier parte del mundo. Inclusive podrán ocurrir situaciones donde dos desarrolladores o empresas estén mutuamente contratados para la ejecución de varios proyectos. También podrán darse alianzas estratégicas entre los desarrolladores y las empresas de software, con el fin de garantizar su estabilidad a largo plazo, dando pie a la creación de nuevas y más sólidas compañías. Y más aún, entre los desarrolladores podrán surgir acuerdos de colaboración para la fabricación de paquetes de software comerciales, compartiendo riesgos (en este caso se sugiere emplear, en lugar de colaborativo, el término cooperativo, distinguiendo dos tipos de proyectos compartidos que propone el modelo DTE). También es posible que surjan nuevas empresas especialistas DTE. Que no nos extrañe ver el surgimiento de compañías especializadas en AN, CC, DC, etc., además de las de DG y PB (componentes), las cuales ya son algo comunes.
En un equipo de desarrolladores debe existir por lo menos un programador bibliotecario, cuya definición que propongo es esta:
Desarrollador encargado de elaborar, adquirir, investigar, administrar y facilitar recursos técnicos a otros desarrolladores, principalmente a los que se encuentran dentro de su grupo o equipo de trabajo.
El bibliotecario debe programar y mantener una biblioteca de funciones, componentes y otros recursos de software prefabricados, cuyos elementos sean creados como soluciones a necesidades reales, reportadas por los demás programadores en sus respectivos proyectos. También debe encargarse de evaluar los requerimientos de los programadores, hacer investigaciones al respecto y en su caso solicitar y / o adquirir los recursos que sean necesarios para satisfacer tales requerimientos. Además el bibliotecario, en la medida de lo posible, debe ser intuitivo, analítico, suspicaz, metódico, imaginativo, perspicaz, persuasor, disuasivo y cuestionante respecto a las peticiones que le hacen sus compañeros, pero sobre todo debe apoyarlos, entenderlos, y ponerse en sus zapatos para determinar qué es lo mejor que se puede hacer en cada caso que le plantean.
Supongamos que Pascual es el programador bibliotecario, y Lorena y Roberto dos de los programadores finales (los que realizan la programación de alto nivel y ensamblado final del producto). En determinado proyecto, Lorena se ve en la necesidad de convertir un arreglo abierto de enteros Array Of Integer, en una cadena de caracteres String separada por comas. Por ejemplo, necesita convertir el arreglo de enteros [78, 27, 2, 19] a la cadena '78, 27, 2, 19' (considerando que el vector de enteros es variable). Lorena intuye que esta necesidad pudo haberse presentado antes en algún otro proyecto del equipo, así que lo primero que hace es plantearle su caso a Pascual, el bibliotecario:
—Mira. Este procedimiento de nuestro proyecto recibe un arreglo abierto de enteros. Se me facilitaría mucho poder convertir el arreglo recibido en una cadena tipo lista separada por comas, porque así podría darla como parámetro al llamar a este método que espera un String. Creo saber cómo realizar la conversión, pero quizá alguien más pudo haber necesitado algo así antes. ¿Tendrás algo para estos casos? Si no, te sugiero tomarlo en cuenta, porque eventualmente podría presentarse de nuevo esta necesidad.
—¡Este es tu día de suerte, Lorena! —le responde Pascual—. Sabes, hace algunas semanas Roberto me planteó un caso muy similar. Desde entonces tenemos en la unidad Convertidores.pas de nuestra biblioteca, una función llamada EnterosALista que hace precisamente la conversión que requieres de Array Of Integer a String. Se usa de esta manera...
—¡Órale, me impresionas Pascual! Me has ahorrado algunas horas de trabajo y medio dolor de cabeza, je-je-je. Muchas gracias, niño listo.
El anterior es un ejemplo de cómo interviene el bibliotecario en la solución de necesidades técnicas de los programadores finales. Se destaca la importancia que tiene en el manejo efectivo de los recursos del equipo, y se observa cómo los programadores finales no se desvían de su objetivo principal, ya que varias tareas adyacentes le son delegadas al bibliotecario.
Si les interesa conocer las opiniones de algunos colegas respecto a la DTE y la figura del bibliotecario, les recomiendo ampliamente echarle una mirada a estas sanas discusiones:
http://www.clubdelphi.com/foros/showthread.php?t=25463
http://www.clubdelphi.com/foros/showthread.php?t=6559
http://www.clubdelphi.com/foros/showthread.php?t=64236
El tercer enlace es un grato testimonio del éxito que ha tenido una pequeña empresa de software de la ciudad Córdoba, en México, respecto de la figura del bibliotecario.
Espero sus opiniones vertidas a través del enlace / recuadro de comentarios que ven debajo de estas líneas.
Un abrazo especializado.
Al González. :)
domingo 17 de mayo de 2009
Lentamente
Espero disfruten este pedazo de arte tanto como yo.
No soy un gran aficionado a esta música, pero es de reconocer que el video está muy bien trabajado.
no podrás curarte despistando al corazón...
Un tentador abrazo.
Al González. :)
martes 28 de abril de 2009
Pandemia de gripe
Antes que nada quiero agradecer a Luis Peña, Heberto Coss y Esteban Arias las atenciones y hospitalidad que tuvieron conmigo durante mi visita a Guadalajara. Espero les haya dejado algo bueno mis exposiciones sobre Delphi, dentro de las limitantes que se presentaron.
Entrando al principal tema en la agenda del mundo, quiero decirles que esta podría ser la primera pandemia que me toque presenciar, deseando de todo corazón que esto no llegue a ocurrir en carne propia de ninguno de mis lectores, ni de mí. Uno de mis hermanos mayores y su familia salieron esta mañana hacia un paraje alejado de la ciudad donde viven, ya que su apartamento se encuentra ubicado muy cerca de dos concurridos hospitales. Permanecerán en aquel lugar por tiempo indefinido para prevenirse de la influenza.
El que más me preocupa, ya que no he logrado localizarlo, es mi hermano menor, el médico, quien apenas lleva dos meses como habitante de Ciudad de México y por quién seré nuevamente tío. Él y su esposa acaban de concebir al que será su primogénito y mi séptimo sobrino. Parece que ya sólo falto yo de fecundar un óvulo, aunque sinceramente no es algo que me atraiga mucho hacer, viendo cómo está el planeta y habiendo tantos niños huérfanos sufriendo hambre. Hermano, espero te encuentres bien, haznos saber cómo lo están pasando tú y mi cuñada. Cuídense mucho, no escatimen precauciones.
El resto de mi familia, por encontrarse poco más al norte del Trópico de Cáncer —una región con menor densidad poblacional— corren un riesgo relativamente menor. Mientras yo sigo aquí, viviendo justo entre la dos ciudades más grandes del país, en una provincia empobrecida por los políticos insensibles de toda la vida, a pesar de ser la tierra del mejor presidente que ha tenido México (y aclaro que no me refiero al actual ;)).
Encontré este documental que relata una historia ficticia que podría estar volviéndose una terrible realidad. Trata de una supuesta pandemia de gripe aguda que podría desatarse en cualquier momento de un futuro cercano. El problema es que ese futuro parece estar sufriendo ya la metamorfosis que lo convierte en presente.
En este material se explica con argumentos sencillos, pero científica e históricamente válidos, cómo se origina y se propaga por el mundo una nueva y muy maligna cepa del virus de la gripe. Decidí incrustarlo en esta bitácora por dos razones principales (algunos dirían “embeberlo”, pero este palabro, por cierto, muy mal relacionado con embed, me recuerda al sucio y desgastado trapo de Magitel con que mi madre me ordenaba contener las bebidas derramadas accidentalmente antes de que la mesa y la física molecular crearan una delgada película con el líquido).
Esas razones son el dar a conocer algunos puntos interesantes que son poco conocidos sobre la gripe y mostrar la asombrosa semejanza que el documental del 2005 guarda con la realidad actual. Una de las revelaciones que llamó más mi atención es que no existen suficientes antivirales para todos los seres humanos en caso de presentarse una nueva pandemia de gripe aguda, y esto es por la sencilla razón de que hasta la fecha los gobiernos no se han propuesto financiar una masiva y necesaria fabricación de tales medicamentos. Como lo dice uno de los entrevistados, parecen estar más interesados en otras cosas.
Esperemos que esta pandemia potencial no pase de ser un conato, que alguna muy buena validación le aplique un temprano Exit. Sin olvidar el hecho de que nuestras precauciones individuales determinarán cuándo ocurrirá esa salida.
Un abrazo por escrito (para evitar contagios).
Al González. :)
lunes 6 de abril de 2009
Funciones de GH Freebrary. Parte 3.- ghEquals, ghEqualStrs, ghFormatOptional, ghFormatStr y ghInc (unidad GHFStrings).
Empiezo con un breve paréntesis para comentarles que ya tengo las fechas para las asesorías de programación que daré en Guadalajara, México. Serán los días 25, 26 y 27 (sábado, domingo y lunes) de este mes de abril. Espero alternar con varios de los lectores que viven o trabajan en esa maravillosa metrópoli y municipios cercanos. Aparte del trabajo que iré a realizar, sugiero que nos reunamos en grupo en alguna cafetería, escuela u oficina para hablar de los temas que nos inquietan como desarrolladores de software y, si se presta la ocasión, llevar a cabo un pequeño taller Delphi.
Bien, a continuación les presento la tercera parte del tema Funciones de GH Freebrary, dándoles a conocer cinco funciones más para el manejo de cadenas de caracteres.
ghEquals
Declaración que tiene:
Function ghEquals (Const Value1, Value2 :String; Const CompareType :TghStrCompare = ghstcInsensitive) :Boolean; Overload;
Descripción corta:
Compara dos cadenas de caracteres (Value1 y Value2) y devuelve True si éstas son iguales, o False en caso contrario.
Ejemplo de uso:
{ Dado el tipo de documento 'Cotización', verificamos si es "esencialmente", es decir, sin importar el tamaño de letras ni si lleva o no algún acento, lo mismo que 'COTIZACION' }
TipoDoc := 'Cotización';
If ghEquals (TipoDoc, 'COTIZACION', ghstcEssential) Then
ghEqualStrs
Declaración que tiene:
Function ghEqualStrs (Const Values :Array Of String; Const CompareType :TghStrCompare = ghstcInsensitive) :Boolean;
Descripción corta:
Devuelve True si todas las cadenas de caracteres de un arreglo dado son iguales, o False en caso de que una o varias sean diferentes al resto.
Ejemplo de uso:
{ Si el usuario introduce por tercera vez consecutiva el mismo código, sin importar el tamaño de letras }
If ghEqualStrs ([CodAnt1, CodAnt2, Edit1.Text]) Then
ghFormatOptional
Declaración que tiene:
Function ghFormatOptional (Const Format, Param :String) :String;
Descripción corta:
Permite dar formato a una cadena de caracteres llamando a la función nativa Format con los parámetros dados, pero sin dejar espacio alguno en la posición del argumento Param si éste es una cadena vacía.
Ejemplo de uso:
{ Mostramos una ventana de mensaje indicando que no es correcto el valor del cuatro de texto Edit1, previendo que pueda tratarse de una cadena vacía }
ShowMessage (ghFormatOptional ('Es incorrecto el valor%*s, por favor verifique.', Edit1.Text));
Resultado cuando Edit1 tiene un valor de 100:
Resultado cuando Edit1 está vacío:
ghFormatStr
Declaración que tiene:
Function ghFormatStr (Const Format, Str :String) :String;
Descripción corta:
Da formato a una cadena de caracteres llamando a la función nativa Format con los parámetros proporcionados, pero devuelve una cadena vacía en caso de que ese sea el valor del argumento Str.
Ejemplo de uso:
{ Establecemos una leyenda en la etiqueta Label1 indicando la calle con la que el domicilio hace esquina, pero solo si tal circunstancia ocurre }
Label1.Caption := ghFormatStr ('(esq. con %s)', CalleEsq);
ghInc
Declaración que tiene:
Function ghInc (Const Value :String; Const Inc :Integer = 1) :String; Overload;
Descripción corta:
Devuelve la cadena de caracteres Value, incrementando en Inc unidades su parte final numérica. Si la cadena Value no termina en un dígito decimal, el resultado será equivalente a la expresión Value + IntToStr (Inc).
Ejemplo de uso:
{ Dada la clave 'AT-07', obtenemos la que subsigue aritméticamente, o sea 'AT-08' }
Clave := 'AT-07';
ClaveSig := ghInc (Clave);
¿Qué opinan de estas cinco funciones y las 10 anteriores que describí? Toc, toc, ¿hay alguien ahí, o ya salieron todos de vacaciones? ;)
Un abrazo en primavera.
Al González. :)
martes 17 de marzo de 2009
Enseñando Delphi en Guadalajara
Explicaré temas relacionados con programación orientada a objetos, bases de datos, componentes, uso del depurador, opciones del IDE, directivas de compilación, ayudantes de clases (class helpers) aplicaciones multi hilo, API de Windows, punteros, manejo de memoria, buffers, streams, RTTI, dbExpress, TClientDataSet, transacciones y concurrencia, DLLs, manejo adecuado de excepciones (Try-Finally, Try-Except), clonación de objetos, encadenamiento de eventos, tipos de datos, valores procedimentales (punteros a rutinas y callbacks), archivos Ini, portapapeles, cuadros de diálogo, redondeo numérico, procesos Windows, sistema de archivos (rutas, directorios, extensiones), cadenas de caracteres, variantes, fechas y horas, moldeo de tipos (type casting), sintaxis del lenguaje, mensajes del sistema operativo, establecimiento de ganchos (hooks), clases interpuestas, manejo de bits y sus operadores (And, Or, Not, XOr, Shl, Shr), lenguaje ensamblador incrustado, emulación del teclado, registros con parte variante, automatización de Word y Excel, trucos y todo aquello que sea de inquietud para ustedes y no esté fuera de mi experiencia personal.
El formato es simple: el asesorado me plantea una inquietud o caso (ya sea genérico o concreto, incluso de un proyecto real) y lo desarrollamos / resolvemos en mi computadora o en la suya. En ello veremos de forma práctica y bien explicada varios de los temas mencionados. El costo es de 300 pesos por hora efectiva. El aprendizaje está garantizado (la asesoría es gratis si la persona siente que no le resulta provechosa).
Y, desde luego, les dejo una copia debidamente comentada de todo el código fuente escrito.
Para mayores informes, comuníquense conmigo al teléfono 01 443 314-2467 o escríbanme al correo de costumbre. Daré algunos descuentos bajo condiciones particulares.
Muy buen día.
Al González. :)
P.D. Próximamente lo repetiré en otras ciudades del país.
sábado 28 de febrero de 2009
El DataSource extendido. Parte 1.
Cheché ha elaborado otro video ilustrativo de los componentes que he venido desarrollando en los últimos años. En este caso se trata del componente TMagiaDataSource, el cual forma parte de la suite Magia Data.
En términos francos, este componente viene a resolver dos antiguos problemas que durante años hemos tenido muchos programadores Delphi a la hora de crear algunas de nuestras aplicaciones de bases de datos. El video anterior muestra cómo el nuevo componente soluciona ambos problemas, pero intentaré describir éstos con detalle.
Supongamos que dentro de un módulo de datos tenemos un componente data set (en español conjunto de datos), el cual puede ser de cualquier clase (TQuery, TTable, TIBQuery, TADOQuery, TClientDataSet, TpFIBDataSet, TMDOQuery, TkbmMemTable, TOraQuery, etc.) y queremos asociar ese conjunto de datos a los controles (componentes visuales) de un formulario. Para esto, normalmente agregamos un componente TDataSource que sirve como canal de comunicación entre el conjunto de datos y los controles de datos que están presentes en el formulario. El componente TDataSource puede ser colocado en el módulo de datos, junto al data set asociado, o bien dentro del propio formulario.
Hasta ahí todo es RADmente bello, lo reconozco desde aquel glorioso otoño boreal de 1997 en que comencé a conocer Delphi. Pero analicemos las complicaciones que suelen surgir en la práctica.
Problema número 1: Los formularios tienden a “apropiarse” de los conjuntos de datos.
Si colocamos un componente conjunto de datos dentro de un data module es porque pensamos centralizar dentro de ese contenedor la tabla, grupo de tablas o acción que representa el componente. De tal manera que quede disponible al uso que diferentes formularios y procesos quieran hacer de él. En términos de programación escrita, es como declarar una nueva constante o tipo de dato para que pueda ser utilizada por diferentes rutinas del programa, sin tener que repetir la declaración o valor literal de dicho elemento global en cada una de éstas, bastando una mera referencia a su nombre (identificador).
Pero un conjunto de datos no es algo fijo, es un objeto con un montón de propiedades, métodos y eventos. Algo que puede cambiar conforme se le utiliza. Entonces diríamos que, en términos de programación escrita, más bien es como una variable global, y los formularios son como las rutinas que usan y modifican esa variable global.
Sólo que existe una gran diferencia que carboniza a esa analogía. Una rutina que modifica el valor de una variable global lo hace conscientemente, asumiendo que eso afectará a las demás rutinas que la empleen. Hay cierta armonía y respeto hacia la esencia de una variable global, ésta existe para ser un contenedor global de datos. Pero con frecuencia colocamos data sets en el interior de un data module, no para hacer de ellos unas especies de variables globales, sino para definirlos en un solo punto, estableciendo en tiempo de diseño las propiedades y eventos que deberán observar los conjuntos de datos cuando vayan a ser utilizados por algún proceso o formulario.
El código asociado a un formulario suele parametrizar, abrir y cerrar conjuntos de datos, cambiando varias de sus propiedades, como Active, Params, ReadOnly, IndexFieldNames, Filter, Filtered, etc. Es un formulario particular que altera a un objeto globalmente definido. ¿Qué debe hacer un formulario así antes de cerrar, cuando ya ha terminado de trabajar con el conjunto de datos? ¿Debe dejarlo tal cual está? Deberá cerrarlo, dirán algunos. Correcto, ¿pero que hay de todas aquellas propiedades y parámetros que el formulario ya le estableció o modificó al componente? ¿Abandonamos la playa cual spring breaker?
En muchas ocasiones, si hay libertad de abrir por segunda vez el formulario (creando una nueva instancia o simplemente haciéndolo visible), éste o su código debe contemplar que el conjunto de datos (que se encuentra en un data module) pudo sufrir modificaciones anteriormente. ¿Acaso el formulario debe deshacer esas modificaciones antes de empezar a usar el conjunto de datos, o debería deshacerlas al terminar de usarlo, digamos, al destruirse la instancia del formulario? De ahí surge la idea de que a veces sería conveniente que cada vez que un formulario se creara o abriera, los conjuntos de datos que utiliza se pusieran en automático tal como fueron definidos en tiempo de diseño.
Una salida falsa es remover el data set del módulo de datos y colocarlo dentro del propio formulario. Así cada vez que se cree una instancia del formulario obtendremos también una nueva instancia del conjunto de datos, tal como fue definido en tiempo de diseño. Pero ésta no es una solución efectiva porque a la larga terminamos “involucionando” (en Delphi 1 no existían los data modules). Al hacer eso, nuestro conjunto de datos deja de ser un objeto globalmente definido, ya no es algo que esté elegantemente disponible para toda la aplicación. Si después agregamos otros formularios que necesiten del mismo conjunto de datos, terminaremos con varias copias de éste regadas por todos lados. Y un mal sueño se materializará cuando haya que hacerles algún cambio, por modificaciones a la estructura de una tabla, al formato de despliegue de algunos de sus campos, etc.
No nos perdamos, los conjuntos de datos viven mejor en los módulos de datos.
Pero la responsabilidad inherente a que un formulario modifique algunos parámetros o propiedades del conjunto de datos es sólo la arista de un gran cubo de hielo. Hay algo todavía más gordo: a veces necesitamos usar la misma tabla o consulta en dos puntos distintos de la aplicación, pero simultáneamente. Eso es común con formularios múltiples no modales que presentan información extraída con la misma consulta SQL, pero estableciendo parámetros o filtros distintos. Naturalmente, esto no es viable mediante el uso de un solo data set. Y aún en casos más sencillos, donde se quiera o se tolere que dos o más formularios abiertos muestren el mismo cursor, resulta que la navegación en uno de los formularios afectará a lo que el otro esté mostrando (imagine, por ejemplo, que hay una rejilla en cada uno, y el usuario cambia de fila en una de ellas; la otra rejilla también cambiará).
Ante esto, otra salida falsa es acompañar a cada instancia de un formulario con una instancia particular de un módulo de datos que contenga solo los data sets que el formulario requiera. A mediano plazo, la aplicación terminará con una cantidad de módulos de datos difícil de administrar y mantener, duplicando en tiempo de diseño muchos conjuntos de datos (algo que se buscaba evitar) y complicando las relaciones entre ellos. O habrá quien sacrifique una buena cantidad de memoria creando nuevas instancias de un gran módulo de datos, para formularios que solamente utilizan un par de data sets.
Estas dos salidas falsas van en dirección a lo que sería un modelo ideal, pero no lo consiguen. Ese modelo consiste en que un conjunto de datos pueda ser definido en tiempo de diseño en un solo punto global, pero que en tiempo de ejecución puedan crearse tantas copias locales de él como resulte necesario. Es decir, que el conjunto de datos definido en tiempo de diseño sea un objeto patrón, del cual puedan crearse clones en tiempo de ejecución.
Pues, señores, eso es lo que obtenemos con la propiedad DataSetCloned del componente TMagiaDataSource. Me cito a mi mismo con este texto de la referencia técnica:
En tiempo de ejecución, cuando esta propiedad tiene un valor de True, el componente toma el conjunto de datos que tenga o sea asignado a la propiedad DataSet, y crea una copia del mismo. Todas las propiedades, eventos y campos definidos del primer conjunto de datos serán establecidos de igual manera en el objeto clon. Y éste será el nuevo conjunto de datos asignado al componente. Esto permite establecer en tiempo de diseño varias fuentes de datos apuntando al mismo conjunto de datos, pero logrando que en tiempo de ejecución cada una use un objeto distinto para evitar conflictos entre formularios o procesos. Es una excelente alternativa a la tradicional y molesta solución de establecer dos o más conjuntos de datos similares en tiempo de diseño, para satisfacer necesidades que podrían tener conflicto si emplearan el mismo componente de datos. Su valor predeterminado es False.
Como se observa en el video, hay dos formularios que muestran datos, cada uno con un componente TMagiaDataSource en su interior, los cuales están enlazados al mismo conjunto de datos patrón en tiempo de diseño (sus propiedades DataSet apuntan al mismo objeto). Pero se les ha puesto la propiedad DataSetCloned en True para que en tiempo de ejecución cada formulario opere con su propia consulta. O sea que cada DataSource usará realmente un clon del objeto asignado en la propiedad DataSet.
En la siguiente entrada describiré el segundo problema y cómo es resuelto con la otra nueva propiedad del componente (DataSetEvents). Por lo pronto el video de arriba les habrá dado una idea de las grandes ventajas logradas con ambas.
Un abrazo extendiendo a Delphi.
Al González. :)
sábado 14 de febrero de 2009
¿Qué empresa NO tiene presencia en YouTube?
Así pues, en Sistemas GH hemos decidido incursionar en este nuevo mundo de difusión global. Para empezar, Cheché (mi colaborador más cercano), ha creado y subido este par de videos sobre Magia Doc, una de nuestras más populares soluciones Delphi para exportación de datos a Word y Excel, la cual emplea plantillas .dot y .xlt que el propio usuario define, dándole con esto la posibilidad de crear cientos de diseños distintos para sus reportes sin intervención mayor del programador en esa que a veces resulta una tediosa tarea con los reporteadores convencionales.
Magia Doc en Delphi - exportando a Word
Demo solución Excel con Delphi
Espero no demorar mucho en preparar videos sobre otras tecnologías, como GH Freebrary y Magia Data, las estrellas de nuestras dos principales líneas de componentes (GH y Magia). Todos los videos que publiquemos estarán disponibles en esta dirección Web: http://www.youtube.com/user/SistemasGHDelphi
No dejen de emitir sus valiosos comentarios.
Un abrazo entubado.
Al González. :)
sábado 17 de enero de 2009
La historia entendible de Palestina
Después de haber visto en su totalidad esta obra de aproximadamente dos horas de duración, creo que guarda un enorme valor histórico por sus explicaciones coherentes e ilustradas de los hechos políticos y demográficos ocurridos en el pueblo palestino, desde los últimos años del Imperio Otomano hasta el fin de la Guerra Fría. En ella aparecen fotografías y filmaciones exquisitas, dignas de cualquier biblioteca, testimonios de la vida palestina en más de cien años de injusticia e inconformidad sociales, y retratos vivos de muchos líderes internacionales en el momento mismo de sus más célebres declaraciones.
Esta producción de France 3 y Point du Jour, titulada Palestine: histoire d'une terre, es por sí misma un llamado a equilibrar la Historia, para no terminar olvidando parte de los hechos más importantes del siglo XX. Su difusión me parece culturalmente obligada, y ya sabemos que a los programadores Delphi, por lo general, no nos gusta quedarnos atrás en estas cuestiones. Vamos siempre en búsqueda de la verdad científica de las cosas, y no nos conformamos con usar While todo el tiempo a sabiendas de que existe Repeat. Al final de la narración, Simone Bitton y Jean-Michel Meurice causan un hondo respiro de comprensión en los espectadores de su brillante trabajo.
El fanatismo es uno de los peores enemigos de las personas, y es imposible que dos personas fanáticamente antagónicas convivan en el mismo espacio. Es imperioso desechar ciertas posturas y creencias radicales y poco constructivas, para lograr vivir en paz al lado de quien piensa distinto.
NOTA: Hay un pequeño “bug” matemático en uno de los subtítulos. Asumo que se trató de un error en la traducción, pero si alguien tiene sus oídos entrenados en el idioma francés, le agradecería me confirmara lo anterior. ;)
Parte 1
Parte 2
Un abrazo rescatando hechos.
Al González.
viernes 26 de diciembre de 2008
Funciones de GH Freebrary. Parte 2.- ghCased, ghCopy, ghCorrelStr, ghCount y ghCountTo (unidad GHFStrings).
He comenzado a redactar una especie de manual de bolsillo sobre las funciones contenidas en GH Freebrary. Decidí iniciar con las que son para el manejo de cadenas de caracteres, las cuales pertenecen a la unidad GHFStrings. En breve incluiré dicho manual en el paquete de descarga de la biblioteca, y conforme vaya agregando más información en el mismo publicaré el nuevo material en esta bitácora también.
En sus marcas, ¿listos? ¡fuera!
ghCased
Declaración que tiene:
Function ghCased (Const Value :String; Const Upper :Boolean) :String; Overload;
Descripción corta:
Convierte una cadena de caracteres al tamaño de letras indicado por el parámetro Upper (True = mayúsculas, False = minúsculas).
Ejemplo de uso:
{ Aseguramos que el nombre de una tabla esté en minúsculas sólo cuando la base de datos sea MySQL, en mayúsculas para los demás casos }
TableName := ghCased (TableName, Not (Server = 'MySQL'));
ghCased
Declaración que tiene:
Function ghCased (Const Value :String; Const ACase :TEditCharCase) :String; Overload;
Descripción corta:
Convierte una cadena de caracteres al tamaño de letras indicado por el parámetro ACase (ecNormal, ecUpperCase, ecLowerCase). Si ACase es ecNormal, devuelve la cadena dada tal como está.
Ejemplo de uso:
{ Asignamos a la variable Leyenda la palabra "nombre" seguida por el texto contenido en Edit1, todo bajo el tamaño de letras restringido de Edit1 para darle uniformidad }
Leyenda := ghCased ('Nombre: ', Edit1.CharCase) + Edit1.Text;
ghCased
Declaración que tiene:
Function ghCased (Const Value, Sample :String) :String; Overload;
Descripción corta:
Convierte una cadena de caracteres al tamaño de letras que tenga otra cadena (parámetro Sample). Si la cadena de muestra Sample tiene letras de ambos tamaños (mayúsculas y minúsculas), devuelve la cadena Value tal como está.
Ejemplo de uso:
{ Aseguramos que el texto de Edit2 esté bajo el mismo tamaño de letras que el texto de Edit1 }
Edit2.Text := ghCased (Edit2.Text, Edit1.Text);
ghCopy
Declaración que tiene:
Function ghCopy (Const Value :String; Const StartIndex :Integer) :String; Overload;
Descripción corta:
De una cadena de caracteres dada, devuelve la subcadena que va desde la posición StartIndex hasta el último carácter.
Ejemplo de uso:
{ Obtenemos el tipo de un componente sin el prefijo "T" de su clase }
CompType := ghCopy (Component.ClassName, 2);
ghCopy
Declaración que tiene:
Function ghCopy (Const Value :String; Const StartIndex, EndIndex :Integer) :String; Overload;
Descripción corta:
De una cadena de caracteres dada, devuelve la subcadena que va desde la posición StartIndex hasta la posición EndIndex.
Ejemplo de uso:
{ Dado el código "DE-97124/A2", obtenemos el número contenido en él desde la posición 4 hasta antes del sufijo "/A2", considerando que el número y ese sufijo pueden ser de longitud variable. }
Code := 'DE-97124/A2';
Number := ghCopy (Code, 4, Pos ('/', Code) - 1);
ghCorrelStr
Declaración que tiene:
Function ghCorrelStr (Const Values :Array Of String; Const Str :String; Const CompareType :TghStrCompare = ghstcInsensitive) :String;
Descripción corta:
De un arreglo de pares de cadenas de caracteres (Values), dada la cadena Str, devuelve la cadena que hace par con ella dentro del arreglo, es decir, su cadena correlativa. Devuelve como resultado la propia cadena Str si ésta no se encuentra dentro del arreglo Values.
Ejemplo de uso:
{ Obtenemos el nombre del producto asociado al fabricante HK-Software (IBExpert) }
Product := ghCorrelStr (['DT/Studio', 'Embarcadero', 'IBExpert', 'HK-Software', 'Magia Data', 'Sistemas GH'], 'HK-SOFTWARE');
ghCount
Declaración que tiene:
Function ghCount (Const Value :String; Const Chr :Char; Const StartIndex :Integer = 1; EndIndex :Integer = MaxInt) :Integer; Overload;
Descripción corta:
Devuelve el número de veces que aparece el carácter Chr dentro de la cadena Value, desde la posición StartIndex hasta la posición EndIndex.
Ejemplo de uso:
{ Si la clave del libro no lleva cuatro guiones }
If ghCount (ISBN, '-') <> 4 Then
ghCount
Declaración que tiene:
Function ghCount (Const Value :String; Const Chrs :TSysCharSet; Const StartIndex :Integer = 1; EndIndex :Integer = MaxInt) :Integer; Overload;
Descripción corta:
Devuelve el número de veces que aparece alguno de los caracteres del conjunto Chrs dentro de la cadena Value, desde la posición StartIndex hasta la posición EndIndex.
Ejemplo de uso:
{ Si el código contiene operadores matemáticos }
If ghCount (Code, ['+', '-', '*', '/']) > 0 Then
ghCountTo
Declaración que tiene:
Function ghCountTo (Const Value :String; Const Chr :Char; Const EndIndex :Integer) :Integer; Overload;
Descripción corta:
Devuelve el número de veces que aparece el carácter Chr dentro de la cadena Value, desde el inicio de la misma hasta la posición EndIndex.
Ejemplo de uso:
{ Obtenemos la cantidad de nombres de campos puestos y separados por punto y coma en la variable FieldNames, sin contar el punto y coma que se dejó al final de la cadena }
FieldNames := 'ID;FirstName;LastName;';
FieldCount := ghCountTo (FieldNames, ';', Length (FieldNames) - 1) + 1;
ghCountTo
Declaración que tiene:
Function ghCountTo (Const Value :String; Const Chrs :TSysCharSet; Const EndIndex :Integer) :Integer; Overload;
Descripción corta:
Devuelve el número de veces que aparece alguno de los caracteres del conjunto Chrs dentro de la cadena Value, desde el inicio de la misma hasta la posición EndIndex.
Ejemplo de uso:
{ Obtenemos la cantidad de operaciones matemáticas de esta fórmula, descartando el texto que inicia con "//" }
Formula := '((A + B) / C) - D // Precio especial';
Ops := ghCountTo (Formula, ['+', '-', '*', '/'], Pos ('//', Formula) - 1);
Espero que esta breve enumeración haya sido de su agrado e interés. Seguiré describiendo más funciones de la unidad GHFStrings en las próximas entregas. Admito que estas descripciones son breves, apenas para un manual de bolsillo, pero es un primer paso en la documentación de GH Freebrary.
No dejen de transmitirme sus opiniones. Sus comentarios son muy valiosos para mejorar lo que esta bitácora ofrece por medio de mis teclado y pensamiento. Me ofrezco a contestar todas las dudas que tengan respecto al uso de estas y otras funciones de la biblioteca.
Un abrazo encadenado.
Al González. :)
domingo 30 de noviembre de 2008
Funciones de GH Freebrary. Parte 1.- Introducción.
Desde que subí los fuentes a la página de Sistemas GH, hace unos cuatro meses, GH Freebrary ha sido descargada ¡más de 150 veces! No tengo una idea clara de quiénes, para qué y cómo la estén usando, cosas que por supuesto me gustaría saber (ahí les encargo ;)), pero me sorprende y congratulo por la cantidad de descargas que han tenido estos archivos .pas, ya que una de mis pequeñas contribuciones técnicas comienza a ser reconocida.
Todas estas rutinas fueron escritas y actualizadas por un servidor a lo largo de 17 años de programación en Delphi (empezando cuando éste se llamaba Turbo Pascal). Y ahora me dispongo a enumerarlas mediante una serie de entradas que iré publicando en esta bitácora a lo largo de varias semanas. De esta forma ayudaré un poco a su comprensión y aprovechamiento por parte de los colegas, en lo que el tiempo me da permiso de elaborar una formal y más fecunda guía de la biblioteca.
¿Han usado expresiones regulares a la hora de hacer una búsqueda entre sentencias de código? Los invito a hacer el siguiente ejercicio junto conmigo:
Abran alguno de sus proyectos Delphi en el IDE, de preferencia uno grande o si gustan ese con el que vienen trabajando hace varias semanas. No se preocupen, no les pediré que modifiquen nada. Vamos a hacer algo más interesante.
Cargado el proyecto en el IDE, asegúrense de tener activo el editor de código abriendo cualquiera de las unidades del proyecto. Ahora presionen la combinación de teclas Ctrl+F. Aparecerá una pequeña ventana de diálogo titulada Find Text. Se trata de una poderosísima herramienta de búsqueda integrada en el IDE que poca gente aprovecha de verdad para buscar cosas en el código con descarada precisión. Este cuadro de diálogo también puede ser abierto con la opción de menú Search\Find.
Como pueden observar, contiene dos pestañas tituladas Find y Find in Files. Presionemos Ctrl+Tab para pasarnos a la segunda de esas pestañas. En el cuadro de texto asociado a la leyenda Text to find introduzcamos la siguiente expresión tal como la pongo yo en seguida:
[^A-Z,a-z]gh[A-Z]+
Marquemos las opciones Case sensitive y Regular expressions, y asegurémonos de dejar seleccionado el botón de radio Search all files in project y desmarcada la opción Whole words only.
Hemos preparado una búsqueda. Pero antes de presionar el botón OK les explicaré a grandes rasgos qué es lo que vamos a buscar. Le hemos dicho a Delphi que vamos a buscar una expresión regular estándar en todas las unidades integradas al proyecto. En el texto que escribimos, los corchetes, el acento circunflejo, el guión, la coma, el signo de más y las letras a y zeta se tomarán como caracteres especiales que le ayudarán al buscador a hacer su trabajo. Hemos indicado que busque, en los archivos de código fuente del proyecto, todas las combinaciones de texto que incluyan al par de letras minúsculas “gh”, seguidas por al menos una letra mayúscula —“[A-Z]+”— y precedidas por cualquier carácter que no sea otra letra —“[^A-Z,a-z]“—.
Ahora sí, presionemos el botón OK del cuadro de diálogo para ver qué nos encuentra. Si el lector es ya un usuario de GH Freebrary, es probable que le aparezca como resultado una pequeña lista de todas las líneas de código del proyecto donde el programa está llamando a una función de mi humilde acervo programático. Le hemos ordenado al buscador de Delphi que encuentre todas las referencias a identificadores que lleven el prefijo gh.
No es casual que todas las funciones de GH Freebrary lleven este prefijo. Es una convención con cierto arraigo entre los programadores el prefijar los identificadores de sus bibliotecas con algunas letras que simbolicen su pertenencia a ellas. De esta forma se evitan conflictos por ambigüedad entre identificadores de funciones y clases nativas y aquellos que son de terceras partes, y en general entre fabricantes de bibliotecas de programación y entre componentes de objetivo común. Claro, la búsqueda que hicimos no es del todo perfecta, ya que Delphi además podría encontrar referencias a otros identificadores de programa que llevasen el mismo prefijo sin ser de GH Freebrary, o bien comentarios o constantes String de contenido coincidente. Pero sin duda el soporte de expresiones regulares en la búsqueda de código fuente es estupendo (iba a escribir la hostia :D).
El proyecto que tengo abierto ahora tiene 73 unidades particulares, es decir, sin considerar las plantillas comunes de herencia visual y otras clases del framework que compartimos entre proyectos. Es una aplicación para medición y cobranza del consumo de agua, cuya primera etapa esperamos mis colaboradores y yo terminar este año. Dentro de esas 73 unidades, Delphi encontró 93 referencias a funciones de GH Freebrary. Como pueden argüir entonces, no sólo recomiendo a mis colegas el uso de esta biblioteca gratuita, sino que además y primeramente la empleo en mis propios desarrollos. De hecho todas y cada una de las funciones de esta colección surgieron y fueron probadas en algún proyecto real, desde los programas que me pedían elaborar algunos estudiantes de último grado de ingeniería cuando yo apenas terminaba la carrera vocacional, pasando por mi antiguo sistema de gestión y punto de venta, las aplicaciones de control de peaje que todavía utiliza el gobierno en algunas carreteras de Chihuahua, componentes a medida que me han pedido varios desarrolladores y los propios como Magia Doc y Magia Data, hasta esta aplicación comercial que esperamos agrade a varios municipios durante los próximos años.
Para constancia de lo dicho, aquí una copia simplificada de los resultados obtenidos en mi búsqueda anterior:
200): Result := ghVar (ghConcatenada ([Str ('CalleNombre'), Str (
200): Result := ghVar (ghConcatenada ([Str ('CalleNombre'), Str (
201): 'NumeroExterior') + ghPrefixed (Str ('NumeroInterior'), '-'),
202): ghPrefixed (Str ('ColoniaNombre'), 'colonia ')]));
248): ghEquals (TRecSeragu (Mediciones.LastRec).Periodo, APeriodo) Then
280): If ghEquals (APeriodoAnterior, APeriodo) Then
288): If Not ghEquals (APeriodoAnterior, Incrementado (APeriodo, -1)) Then
356): Agua := Importe + ghMultiply (Consumo - ConsumoPiso,
360): Alcantarillado := ghPercent (Agua, PorcentajeAlcantarillado, 2)
365): Saneamiento := ghPercent (Agua, PorcentajeSaneamiento, 2)
373): IVA := ghPercent (Subtotal, PorcentajeIVA, 2);
392): Result := ghIncUnits (APeriodo, 1, 12, Incremento);
404): With ghDate (Valor) Do
414): Result := ghUnits (APeriodo, 1, 12);
446): Result.PeriodoInicial := ghMax (PeriodoInicial, PeriodoSuspension);
447): Result.PeriodoFinal := ghMin (Incrementado (PeriodoFinal),
660): If Not ghEquals (Consumo.PeriodoInicial, Periodo) Then
980): If (ghPosStr (['Solicitud', 'Presupuesto', 'Contrato', 'Padron',
984): NumeroExterior := ghSeparadaUltima (Values);
986): If ghEsEntero (NumeroExterior) Then
987): Result := VarArrayOf ([ghSinFin (Values,
995): If (ghPosStr (['MedicionConsumo', 'PeriodoFacturacion'], Entity) >
996): -1) And (ghPosStr (['AoPeriodoMinimo', 'AoPeriodoMaximo'], Field) >
261): FacturarContrato (ID, ghTwoInts (PeriodoInicial, AoInicial),
262): ghTwoInts (PeriodoFinal, AoFinal));
295): With ghDate (Fecha) Do
310): Result.Low := StrToInt (ghFinDigitos (Cadena));
321): Result := ghIncUnits (Ao, Numero, 1, PeriodoMayor (), Incremento);
404): Result := (ghUnits (AoFinal, NumeroFinal, 1, Mayor) -
405): ghUnits (AoInicial, NumeroInicial, 1, Mayor)) + 1;
428): If ghEquals (Table + '.' + Field, 'Contrato.IDTarifa') Then
377): //{} Text := ghPesosMayusculas(dtPagosReporteTOTAL.AsCurrency) ;
61): ghAbort ('Datos incompletos','Debe capturar al menos una categoría.',grEntry);
71): ghEnable ([lbPrint, lbDelete], ((ActiveView = vwPago) And
103): If ghAsk ('Cancelar pago',
71): ghAbort ('Datos incompletos','Debe capturar al menos un subconcepto de obra.',grEntry);
428): ghAbort ('Datos incompletos','Debe capturar al menos una tarifa.',
432): If ghFloat (vwEntry.DataController.Summary.FooterSummaryValues [0]) <>
434): ghAbort ('Datos incorrectos',
59): ghAbort ('Dato inválido',
209): ghEnable ([lbFacturar, lbNotificarAdeudo],
213): ghEnable([lbPrint],
252): { With ghCursorSavePoints.Save (crHourGlass) Do
268): ghInform ('Facturación terminada', 'Se facturaron ' +
283): (* ghCursorSavePoints.Save (crHourGlass);
303): ghInform ('Notificación de adeudos terminada',
313): ghCursorSavePoints.Last.Restore;
463): RejillaActiva := TcxGrid (FindComponent ('gr' + ghLeftOf (ghCopy
463): RejillaActiva := TcxGrid (FindComponent ('gr' + ghLeftOf (ghCopy
477): RejillaActiva := TcxGrid (ghContenedor (TcxGrid)) ;
731): ghShowStop ('Alerta', 'Imposible eliminar registro pagado',
764): ghAbort ('Datos incompletos','Debe capturar al menos un detalle de la factura.');
786): ghShowStop ('Importes diferentes', 'El total de pagos es MENOR al total de la factura.');
796): ghShowStop ('Importes diferentes', 'El total de pagos es MAYOR al total de la factura.');
131): ghAbort ('Fecha incorrecta', 'Revise la fecha', edFechaEntrega);
136): ghAbort ('Fecha incorrecta', 'Revise la fecha', edFechaEjecucion);
141): ghAbort ('Fecha incorrecta', 'Revise la fecha', edFechaFuerzaPublica);
146): ghAbort ('Fecha incorrecta', 'Revise la fecha', edFechaEstado);
151): ghAbort ('Fecha incorrecta', 'Revise la fecha', edFechaRemate); }
129): ghAbort ('Datos incompletos',
137): ghAbort ('Dato faltante', 'Si la orden ya fue ejecutada debe ' +
254): ghInform ('Tipo de queja no especificado',
499): If ghEnRango (dmServidor.CurrentDate,
545): (* Adeudo := ghFloat (
547): ghFloat (
552): Total := ghFloat (
554): ghFloat (
576): ghShowStop ('Cantidad inválida',
580): If ghAsk ('Confirmar cantidad',
586): dsEntry ['Importe'] := ghFloat (
620): ghInform ('Pago registrado', 'El pago ha sido registrado. ' +
341): dsDetail['PorcentajeServicios'] := ghPorcentaje (
345): dsDetail['PorcentajeRecargos'] := ghPorcentaje (
349): dsDetail['PorcentajeMultas'] := ghPorcentaje (
353): dsDetail['PorcentajeGastos'] := ghPorcentaje (
489): { Descuentos [0] := ghFloat (
493): { Descuentos [1] := ghFloat (
497): { Descuentos [2] := ghFloat (
501): { Descuentos [3] := ghFloat (
509): ghCadena (I = 0, 'Importe') + Conceptos [I]).AsCurrency Then
513): ghAbort ('Descuentos inválidos',
516): dsFactura.DataSet.FindField (ghCadena (I = 0, 'Importe') +
149): ghAbort ('Datos incompletos', 'Debe especificar al menos una partida.',
192): ghPercent100 (DetailRec.Float ('IVA'),
203): dsDetail.SetQuiet ('IVA', ghDivide (DetailRec ['Importe'] *
207): ghPercent100 (DetailRec.Float ('IVA'),
68): ghAbort ('Datos incompletos','Debe capturar al menos un detalle de la tarifa.',grEntry);
63): Clave := ghSinEspacios (ghSinFin (tbConceptosClave.Value, '0'));
63): Clave := ghSinEspacios (ghSinFin (tbConceptosClave.Value, '0'));
65): If dsConceptoObra.DataSet.Locate ('Nombre', ghUpperFirst (
74): ghUpperFirst (AnsiLowerCase (tbConceptosConcepto.Value));
82): ghSinEspacios (tbSubconceptosClave.Value);
84): ghUpperFirst (AnsiLowerCase (tbSubconceptosConcepto.Value));
Como podrán notar, todavía tengo algunas funciones que no he traducido al idioma inglés (lo voy haciendo poco a poco y más o menos una vez al mes subo una actualización a la Web).
Lo que sigue es empezar a ilustrar cada una de las funciones de la biblioteca. ¡Cómo me gustaría contar con los recursos suficientes para crear una referencia tan buena como la ayuda de Delphi 7! De momento tendré que conformarme con una sencilla enumeración de las funciones, donde explique brevemente la declaración y uso de éstas a partir de la siguiente entrada. No obstante les solicito que vayan enviándome desde ahora sus sugerencias, dudas e inquietudes sobre este tema, a través del sistema de comentarios de esta bitácora o si prefieren por correo electrónico (“algonzalez” y luego “74” [at]correocalienteperoeninglés[punto]com).
Antes de despedirme, dos noticias:
1. Muy pronto estará lista la versión de GH Freebrary para Delphi 2007 y de ahí el salto a Delphi 2009 tendrá escasa demora. Estén pendientes.
2. Esta semana que comienza inicia CodeRage III. Del lunes al viernes habrá exposiciones muy interesantes y en español sobre Delphi y otras tecnologías de desarrollo de Embarcadero. Espero poder asistir a algunas de ellas y tener el placer de saludarlos.
Ahora sí me despido, sólo por unos días.
Un abrazo útil encontrado.
Al González. :)
martes 28 de octubre de 2008
¿Cómo funciona el sistema monetario?
Siento que vale mucho la pena darlo a conocer, ya que la mayoría de las personas suelen ignorar cómo funcionan los principales mecanismos de la economía, por considerarlos confusos y demasiado complejos. Yo, en lo personal, vengo hace tiempo interesándome en los asuntos que tienen que ver con la economía en general, porque me importa comprender dónde están los puntos malos que originan tanta desigualdad en los niveles de bienestar y de qué manera podría contribuir a mejorar el sistema en el que vivimos.
Dejo claro que este material que encontré, y que ahora me percato ha sido dado a conocer en muchos otros sitios serios de la Red, está muy lejos de ser uno de esos seudodocumentales o falsos testimonios de estilo apocalíptico, esquizofrénico, paranoico, conspirativo e hipocondríaco que algunos usan para sentir y hacer sentir protagonismo espontáneo y que detrás de una vida rutinaria y aburrida se encuentra oculto un paraíso de verdades asombrosas. Fantasear es bueno en muchas ocasiones, pero hay quienes se afanan en pulverizar la verdad comprobada con hipótesis tergiversadas, y eso es lo que no procede en un mundo que pretende civilizarse.
Money as Debt es un audaz reportaje del canadiense Paul Grignon, en el cual explica con sencillas animaciones cómo nació y evolucionó nuestro sistema bancario y el manejo que le damos al dinero en los países del llamado libre mercado. Aborda de una manera serena y convincente las inevitables consecuencias que acarrea un sistema monetario tan frágil como el de Estados Unidos de América y otros países. En él podemos observar con luz de cenit cómo es que llegan a quebrar los bancos, la manera en que éstos se relacionan con el gobierno y de qué forma juntos afectan la vida de las personas. La deuda es el elemento primario del documental y me atrevo a asegurar que, después de verlo, más de uno lo pensará dos veces antes de volver a solicitar un crédito.
Un abrazo sin intereses.
Al González. :)
lunes 29 de septiembre de 2008
Presentación de Delphi 2009 en Guadalajara. Lo que se dijo dentro y fuera del evento.
Esta vez tuve oportunidad de asistir a la primera de las dos presentaciones gracias a la amable invitación de los organizadores. Desafortunadamente llegué hasta la hora en que David I. terminaba su intervención sobre las novedades de C++ Builder (ahora sé que la Fuente Olímpica está muy, pero muy lejos de Plaza Galerías y que el Pretrén se paga con importe exacto). La sala de cine donde se llevó a cabo el encuentro estaba prácticamente llena, pareciéndome un lugar muy atinado para dar demostraciones de software multitudinarias ya que estos lugares están diseñados para mantener la atención del público sobre lo que se proyecta en pantalla.
Acomodado en mi butaca, con una camiseta negra extra grande (supongo que ya no había de otro tamaño) y la acostumbrada hoja de comentarios en mano, además del aparato de traducción conectado a mis oídos poco entrenados en el idioma inglés, inició la sesión de preguntas y respuestas con David, la cual duraría entre cinco y diez minutos. Enseguida vendría Andreano Lanusse con el plato fuerte por el que asistieron la mayoría esa mañana al encuentro de Avenida Vallarta: las novedades de Delphi 2009.
Realmente se están esforzando por incluir en cada nueva versión cosas que son importantes para los desarrolladores, pero es algo incómodo reconocer que el mercado ya no está recibiéndolas con el aprecio que comúnmente se le daba en los años noventas a cada nueva versión de un producto de software. Este fenómeno tiende a materializarse con el software de paga que ha alcanzado cierto nivel de sofisticación y calidad, como por ejemplo Windows XP y Delphi 7. En el caso del primero Microsoft supo con tiempo lo que pasaría si no lograban que la siguiente versión fuera radicalmente diferente: la gente simplemente no cambiaría su estable, suficiente y cómodo XP por uno que fuese 90% igual. Así que decidieron arriesgarse intentando inventar un nuevo tipo de rueda, con las catastróficas consecuencias que ya todos conocemos del golpeado Windows Vista.
Borland y el ahora CodeGear de Embarcadero no quisieron correr ese mismo riesgo con Delphi. Es demasiado lo que está en juego y pocas las oportunidades de corregir el rumbo en caso de equivocarse tecnológicamente. Borland estuvo cerca de perderlo todo con Delphi 8 y 2005; CodeGear fue la válvula de escape que se creó para comenzar a rescatarlo. Y desde la versión 2007 optaron por retomar la sensata y conservadora postura de 99.9% de compatibilidad hacia atrás, añadiendo novedades importantes sólo habiéndolas analizado concienzudamente, ya sin grandes precipitaciones. Medida inteligente, sin duda, pero poco agresiva para una compañía a la que le urge capitalizarse y reposicionar a Delphi. No obstante, tengo razones para pensar que ya se estudia en California la posibilidad de hacer algunas grandes reformas a la VCL. Recordemos que muchas de las clases conservan aún la misma estructura general que Borland les dio en los tiempos del Paradox, cuando los programadores éramos un gremio subterráneo y los ratones tenían bolita.
No hablaré en esta entrada de qué es lo que creo que debería hacerse para captar mayores recursos y colocar a Delphi en los primeros lugares. Espero que algunas de las sugerencias que he entregado durante el último año y medio ya estén siendo revisadas por una o varias personas de Embarcadero, y confío en que de todo el planeta les estarán llegando muchas otras aportaciones que nacen del corazón mismo de los desarrolladores que queremos ver a Delphi cual enorme es. El resto de la entrada será para enumerar algunas de las características que fueron incorporadas en Delphi 2009 y dar a conocer varios apuntes interesantes.
- Soporte Unicode. Pensando en que podamos exportar nuestras aplicaciones a mercados europeos y asiáticos sin problemas con los diferentes idiomas de esas regiones.
- Explorador de Clases. Con el cual podemos examinar visualmente las jerarquías de clases y los miembros de éstas. La rama de una clase puede ser visa hacia sus derivados o hacia sus ancestros.
- Nuevas opciones de proyecto.
- Nuevo administrador de proyectos (Project Manager) con directorios y subdirectorios de archivos de código fuente.
- Búsqueda incremental filtrante en la localización de componentes.
- Se incluye gratis la suite de componentes de terceros InfoPower, si la compra se hace antes del 1 de octubre. En esto de las ofertas siguen fallando. Considero que la validez de esta promoción debió extenderse, al menos en México, hasta el 15 de diciembre para que realmente fuese ponderara por el público. Menos de 30 días para aprovechar la oferta hubiese sido poco incluso para la suite DevExpress. Y no porque valgan poco estas bibliotecas de componentes, sino por la habitual resistencia a las actualizaciones que comenté en los primeros párrafos aunada al tiempo que un micro empresario mexicano necesita para asegurar capital y realizar una compra en estos días.
- Se está trabajando de manera coordinada con los principales fabricantes de componentes de terceros para que éstos incluyan sin grandes dificultades el soporte Unicode (nos aseguraron que habrá un QuantumGrid Unicode por parte de Developer Express).
- El procedimiento Exit ahora puede recibir como parámetro el valor a devolver, haciendo con esto las veces de un típico return de lenguaje C. Esto nos ahorrará muchos Begins y Ends en las salidas rápidas de nuestras rutinas.
- Nuevos métodos en TObject (y por lo tanto disponibles en todas las clases): UnitName, Equals, GetHashCode, ToString.
- Nuevo componente TCategoryPanelGroup. Grupo de paneles colapsables contenedores de controles, con imágenes que se alternan conforme se pasa el cursor por encima.
- Soporte para imágenes de formato PNG.
- Componente TImageList mejorado para soportar imágenes de mayor tamaño.
- Nuevo componente TButtonedEdit. Cuadro de texto con botón(es), al cual pueden definírsele imágenes y eventos específicos para los botones izquierdo y derecho.
- Nuevo componente TLinkLabel. Etiqueta de texto con capacidad HTML para presentar, dentro de nuestros formularios, hipervínculos que ejecuten acciones.
- Balloom Hints. Comentarios emergentes que pueden incluir gráficos en su interior y más estéticos que los tradicionales.
- La lista de elementos de un componente TListView ahora puede dividirse en grupos, pudiéndose establecer la imagen a usar para los grupos, además de la imagen usada para los elementos.
- Ribbon Controls. Son controles muy coquetos, al estilo de las últimas versiones de Microsoft Office. No sé mucho al respecto porque yo sigo satisfecho con Office 2000, pero son útiles para acceder rápidamente a las opciones de una barra de herramientas, por ejemplo. Desafortunadamente se necesita una especie de licencia por parte de Microsoft para su integración en las aplicaciones que desarrollemos.
- Tipos genéricos. Es la capacidad de indeterminar o abstraer el tipo de dato que una clase maneja en algunos de sus puntos, con el fin de poder usar dicha clase abiertamente con valores de diferentes tipos. Esta es una de las características que personalmente me parecen más interesantes debido a mi arraigado interés en la evolución del lenguaje Pascal (quién fuera a decir que se otorgaría un segundo uso a los caracteres “<” y “>” además de ser operadores).
- Métodos anónimos. Son rutinas de código sin nombre identificador que pueden ser escritas entre las sentencias de otras rutinas, con el fin de ejecutarlas dos o más veces por medio de una variable de referencia. Una alternativa al uso de subrutinas que me gustaría estudiar con detalle.
- En cuanto a DataSnap, ya no se utiliza COM para comunicación entre las capas y se incluyeron nuevos métodos para hacer llamadas al servidor de aplicaciones. Además se pueden observar en el inspector de objetos los métodos y parámetros exportados por el servidor de aplicaciones, algo que me parece muy práctico.
- Un dato interesante de InterBase 2009 es que incluye criptografía de campos. De manera opcional, cada campo de una tabla puede ser codificado para que sólo ciertos usuarios tengan acceso visual a su contenido. Esto no me hará abandonar a Firebird, pero reconozco que es una buena característica del nuevo InterBase.
En esa misma sesión de intercambio verbal con el público, sugerí a Andreano que analizaran la posibilidad de hacer las presentaciones un poco más tarde, para darle oportunidad a los asistentes foráneos de llegar a tiempo. Amablemente dio a entender que lo estudiarían. Y le pregunté si existía la posibilidad de que lleguemos a ver una licencia de Delphi, edición Professional, a precio competitivo de 500 USD, pero el espíritu de su respuesta fue «mmm, no lo sé, es poco probable».
Posteriormente, en los pasillos del edificio, varios colegas y yo charlamos un buen rato con Raúl Gómez, el director de Gopac, e intercambiamos puntos de vista respecto a las estrategias que el distribuidor oficial está poniendo en práctica para aumentar el uso de Delphi en México. Entre los puntos más interesantes revelados me gustaría destacar los siguientes:
- Embarcadero autorizó, después de largas negociaciones, que Gopac pueda vender Delphi a las universidades mexicanas bajo un esquema especial que les permita a éstas adquirirlo con facilidad y usarlo tanto para enseñanza como para sus propios desarrollos internos. Raúl ha estado supervisando personalmente la nueva estrategia a seguir con las universidades y colegios vocacionales y se muestra muy convencido de tener éxito en la misma. Esto realmente es esperanzador.
- A través de este distribuidor Delphi podrá ser adquirido a crédito, ya no sólo con American Express, sino también con tarjetas de crédito de al menos dos o tres bancos nacionales. Comentó que las negociaciones con dichos bancos están muy avanzadas y que es casi un hecho lo anterior.
- Gopac está en proceso de certificar a un empleado suyo por cada herramienta de CodeGear. Lo que me preocupa de este punto es que la persona correspondiente a Delphi resulte un consultor de altos vuelos y desconozca, por ejemplo, las ventajas de que el método TObject.NewInstance sea virtual. Ojalá resulte ser un verdadero apasionado por la programación, Pascal, Delphi y su historia. Le externé esta preocupación a Raúl (necesitan contar con un hombre o mujer fuerte en Delphi para defender y apuntalar el avance de sus estrategias).
Envío un agradecimiento especial a Gopac por todas las facilidades prestadas.
Un abrazo 2009.
Al González.
sábado 2 de agosto de 2008
¿Qué es GH Freebrary?
Durante la mañana de ese día, en los pasillos de la escuela, le había planteado lo siguiente:
—Profe’, verá, en varios de los programas que hacemos utilizamos algunos procedimientos y funciones que creamos desde las primeras lecciones. Yo mismo he ido creando algunos procedimientos adicionales para cosas que hago con frecuencia en mis programas. El problema es que cada vez que creo un programa, tengo que hacerlo a partir de uno anterior para tener siempre disponibles todas mis rutinas de utilería. Sé que puedo marcar en el editor de Turbo Pascal un bloque de texto y guardarlo con Ctrl+K+W y luego cargarlo en otro archivo con Ctrl+K+R, pero finalmente no dejamos de repetir código. ¿Hay alguna forma de que no tengamos que repetir el código de las rutinas de utilería en cada programa que hagamos?
—La hay, en Pascal existe algo llamado unidades, es la solución para eso que planteas —respondió el profesor cuyo apellido lamentablemente no recuerdo.
Las manos me sudaban al entrar al establecimiento, la ansiedad por descubrir el secreto de las unidades aumentaba conforme me acercaba al área de publicaciones informáticas. Y ahí estaba un libro, no recuerdo el título, pero hablaba de Turbo Pascal y sus bondades; entre ellas, el uso de las palabras reservadas Unit y Uses. No disponía de dinero para comprarlo —habría de transcurrir un año más para comprar el único libro de programación que he adquirido en mi vida—. En esta ocasión me limité a hojearlo frente al estante; más que eso, me puse a leerlo ahí mismo, como quien mira un televisor a través del cristal de la tienda donde lo exhiben. Estaba haciendo uso de una librería como si fuese una biblioteca (lo sé, ¡olímpica ironía mutante!). Estuve alrededor de una hora con las pupilas devorando texto, tratando de memorizar cada concepto, técnica y ejemplo que leía acerca de las unidades del Turbo. El lector debe tener en cuenta que la Internet no era una cosa muy popular que digamos en 1991, así que la mayor parte del conocimiento técnico lo adquiríamos en la escuela y a través de los libros, dos medios poco accesibles en aquél lugar y en aquella época para un estudiante de bajos recursos.
De ahí surgieron, en alguna computadora del laboratorio de cómputo de la escuela, dos semillas llamadas MTR.PAS y MAR.PAS, mis dos primeras unidades de funciones reutilizables. ¿Quieren ver algo de ese antiguo código? Aquí unas muestras:
El siguiente semestre vimos más acerca de Pascal, y en las lecciones el empleo de la cláusula Uses para referirse a unidades propias era algo más cotidiano. Los profesores les llamaban “librerías”, así que también yo comencé a llamarles de esa equivocada manera. Pero los mejores momentos estaban por venir. Para el último año en el CONALEP, cuando mi obsesión por el desarrollo de software (si es que hacer programas donde jugaba con los caracteres ASCII podía llamarse desarrollo de software) alcanzaba el grado de hacerme faltar a las clases de Historia, Cobol y Contabilidad, y privarme de comprender a plenitud el cálculo integral en las clases de Matemáticas, mi “librería” de funciones alcanzaba varias decenas de rutinas que entonces me eran muy útiles en la versión 6 del lenguaje. Una mañana de gran inspiración, durante vacaciones de invierno, entré en hipotermia mientras aporreaba teclas en una máquina del laboratorio de cómputo. Pero aún así me sentía afortunado de que el profesor a cargo me hubiera confiado las llaves por varios días en los que fui sin falta a la desolada escuela, a pesar del terrible viento de hielo que cortaba la piel y que formaba estalactitas en las orillas de los techos. Las instalaciones se encontraban en un descampado típico de las llanuras norteamericanas, en lo que entonces era casi la orilla norte de la ciudad de Chihuahua, zona que siempre ha sido más fría que el acogedor centro.
Terminé mis estudios como Profesional Técnico en Programación y Análisis de Sistemas, mas no hice el trabajo de fin de cursos. Salvé mediante exámenes extraordinarios las materias que había reprobado, como Cobol y Contabilidad y no sé qué otra, pero no me titulé ni mucho menos asistí a las ceremonias y al baile de graduación. Las cosas no andaban bien en casa como para gastar más dinero en mí, lo rechazaba. Además la rebeldía y aparente autosuficiencia de mi carácter ahuyentaban a quienes se interesaban en apoyarme de algún modo, y por si fuera poco atravesaba por una profunda depresión emocional que casi me lleva a darme de baja en los últimos meses de la carrera.
Pero quería seguir programando en Turbo Pascal, así que cuando ya no estudiaba en aulas comencé a estudiar en casa, practicando el uso de Turbo Vision con la versión 7. Ahí fueron mis primeros encuentros reales con la POO. Pasé muchas horas en la habitación que ahora es de mi madre escribiendo y probando código, mucho código, con la primera computadora que tuve, una 8088 de segunda mano que mi hermano Antonio había comprado...¡adivinen donde!: en la tienda que hace un mes me contactó para solicitar el desarrollo de un sistema de software, motivo por el cual vine en esta ocasión a mi tierra natal —¡el mundo y sus vueltas!—. Y mucho de ese código iba a parar a funciones reutilizables y muy atomizadas (la atomicidad dispara al máximo tal reusabilidad) dentro de mi joven biblioteca de rutinas. No recuerdo con precisión si fue en esta época o hasta entrar en el mundo Delphi, cuando me enteré con sorpresa que el término correcto para denominar a estas colecciones de rutinas es biblioteca (library) y no librería (book store). Hoy en día hay menos dudas al respecto, los autores más respetados, y que a su vez se dignan en respetar el idioma español, emplean en sus publicaciones el término biblioteca. Viéndose, por el contrario, el uso del término librería como una falta de cultura.
A finales de 1997 convertí mi biblioteca a Delphi 1, retirando a un gran número de procedimientos y funciones que eran obsoletos para la plataforma Windows, y seguí alimentándola con nuevas rutinas de código que escribía durante los desarrollos que hacía. Para entonces el estilo de mi código fuente había mejorado mucho y se parecía más al que hoy día manejo; durante años fui perfeccionándolo. Lo interesante es que todas esas funciones surgieron de necesidades reales durante los proyectos de software donde participaba. Ya desde el siglo pasado quería compartir mis rutinas con otros programadores para que las emplearan en sus aplicaciones y se facilitaran el trabajo de construir éstas. Pero me creé una estúpida barrera yo mismo al negarles acceso al código fuente, entregándoles solamente los archivos .dcu (mi estimado amigo Emilio Muñoz tal vez recuerde un breve desencuentro al respecto). Entonces pasaba por mi mente la idea de que mi código era tan bueno que nadie o casi nadie más merecía tocarlo —típico signo de inmadurez en algunos desarrolladores jóvenes—.
Pero desde que establecí el foro Web PDM (cuyo objetivo, por cierto, parece haberse cumplido ya), en el verano boreal de 2002, decidí distribuir con todo y código fuente mi vasta, nada documentada y amada biblioteca de funciones Delphi, bajo el nombre de Interfaz GH. Con más de mil rutinas de propósito general, estimo que a la fecha es utilizada por varias decenas de desarrolladores, principalmente de América; aunque la gran mayoría de ellos utiliza sólo unas cuantas de las funciones, por la aún carente documentación. No obstante, me provoca orgullo saber que he puesto en manos de muchos estudiantes y profesionistas una herramienta que es cuando menos útil en sus labores, contribuyendo de paso al fortalecimiento de Delphi. Un diamante diminuto en el arenal de buenas acciones.
El punto crucial de esta historia es que hace tres años decidí hacerle una reforma importante a Interfaz GH: cambiar los nombres de todos sus elementos por identificadores más amigables, ya que hasta entonces empleaba a rajatabla un estricto y fatal estilo de cuatro letras por palabra en los identificadores (cinco cuando se trataba de la primera palabra del nombre de una rutina). Lo sé, andaba yo muy robotizado. Llevar a cabo este cambio con cientos de funciones y sus variables representaba todo un reto. Pero ahí no para la cosa. Unos cuantos meses después de iniciar esa reforma terminé de convencerme de una gran verdad dentro del desarrollo de software: el código fuente de todas las bibliotecas de programación públicas del universo debe estar en un único idioma (y de hecho algún día estarán en un único lenguaje de programación, pero no quiero adelantarme al futuro ;)). Así que detuve la reforma, o mejor dicho, la redefiní, para considerar en estas modificaciones el uso del idioma universal de la programación: el inglés. Es por ello que también cambié su nombre a GH Freebrary, pensando que con él será mayor su difusión internacional.
Actualmente GH Freebrary es un producto relativamente maduro, pero el proceso de humanización que le estoy haciendo va apenas en un 30% o 40%, considerando que no solo estoy cambiando el idioma y el estilo de nombres, sino también revisando algoritmos para detectar aquellos que pueden tener una mejora sustancial, además de eliminar uno que otro procedimiento medio fumado. Sin embargo, podría pasar otro año afinando mi biblioteca antes de dejarla como realmente quiero que esté para ofrecerla en grande, y podría decirse que hasta entonces sería prudente comenzar a promocionarla con el nuevo nombre. ¡Pero llevo toda mi vida adulta gestando esta preciada colección! ¿Por qué no invitar a la gente a emplearla, aprovechando sus bondades desde ahora? Después de todo varias decenas de funciones ya están más que revisadas, convertidas al inglés y las utilizo con éxito todos los días en mis propios proyectos. ¿Por qué privar al público de utilizar dichas funciones hasta que toda la biblioteca esté “perfecta”? El cien por ciento del código es funcional y está probado, su tasa de defectos de operación —bugs— es bajísima (en buena medida gracias a la atomicidad), así que si el único problema es el idioma y el estilo de nombres de un grupo de funciones, ¿por qué no promover al resto de ellas?
Esta positiva reflexión me llevó a colocar un enlace para su libre descarga en la página de mi empresa hace tan solo unas semanas. Y, mientras la gran reforma de GH Freebrary continúa, la recomendación para mis amigos programadores es simple: usar sólo las funciones y otros elementos que ya están en inglés y llevan el prefijo gh, tales elementos se mantienen y se respetarán. Cuando termine con la reforma, el siguiente paso será crear la tan solicitada documentación.
Siéntanse libres para descargarla y usarla en sus proyectos Delphi. Compila en Delphi 7 sin problemas, aunque se aconseja tenerlo actualizado a 7.1 por un pequeño defecto del compilador. Y, como incluye el código fuente, pueden intentar adaptarla a otras versiones si se les presenta esa necesidad. De cualquier manera, en mis planes de corto plazo está el adaptarla a las versiones 2007 y 2009 (Tiburón), y posiblemente a versiones anteriores si el público así lo pide.
Respondiendo a la pregunta con que intitulo a esta histórica entrada, GH Freebrary es literalmente la obra de mi vida, la cual comparto ahora con mucho gusto con todos los programadores Delphi del mundo.
Un abrazo de 17 años.
Al González.
jueves 31 de julio de 2008
Último semestre en el Limbo
Resumí en algunos cientos de palabras cuál era mi vida hace cinco años y algo de lo que ahora soy. Cómo pasé de ser un osado joven de veintiocho años que vivía tan deliciosamente, muy a su manera, en su lúdico hogar de hombre soltero, con sus hábitos contemplativos, el bien comer, el ejercicio físico y una novia atractiva cuyo único defecto era marcharse siempre a media noche; que había logrado el sueño de muchos jóvenes con deseos de independencia en una país donde todavía era costumbre cargar en el bolsillo llaves de un auto antes que llaves de una casa...a ser un empresario pobre, ingenuo, estresado y sin hogar de treinta y tres vueltas al Sol. Mi muy particular sueño americano se gestaba hace cinco años, pero me sacaron de él, contribuí a que sucediera y se rompió el encanto.
Todo parecía estar dictado. Tal vez me lo había ganado por ir más allá de lo que mi noble conciencia toleraba y también por estar tan lejos de los estándares socialmente aceptados. Era admirable mucho de lo que conseguía, pero debo confesar que también pequé de lujuria. El camino que ahora me ponían enfrente, y a donde mi destino me absorbía sin tregua, era un camino de castigos pero también de pruebas y de algunos premios. Era como si los jueces de la Providencia no pudieran ponerse de acuerdo sobre si enviarme al Paraíso o al Infierno, así que decidieron abrirme las puertas del Limbo y mantenerme en observación durante algún tiempo.
Y aquí me tienen, semidesnudo frente a una portátil que no he terminado de pagar, en la habitación que fue de tres de mis hermanos antes de ser la pieza donde duermo cuando vengo de visita a Chihuahua. Cuando camino por las calles veo todo lo hermoso que sería volver a vivir en esta ciudad, pero no tengo la fuerza ni la serenidad necesarias para disfrutar esa fantasía con la intensidad que merece la historia de mis manos. Pasando el otro día frente al llovido, fresco y rocoso Cerro Coronel suspiré por recordar que en otros tiempos, cuando todavía la mayoría de las personas éramos amigos del universo, alimentaba las moléculas de mi pensamiento con adrenalina producida en su lapídeo laberinto de paredes escalables.
Este lugar no quiere que me vaya, y no quisiera dejarlo una vez más. Pero sé que debo terminar mi tesis de mitad de vida y titularme muy al sur del Trópico de Cáncer, donde el paisaje encaja menos con la palabra Norteamérica, donde no hay estaciones para sentirse en paz en otoño, reflexivo en invierno, ilusionado en primavera y activo en verano, sino simplemente temporadas de seca y de lluvia. Ahí donde decidí iniciar una empresa de software que sobrevive porque aquellos jueces saben que menos sería demasiada crueldad, donde reparo mis faltas construyendo un nuevo sueño, ahora compartido, que algunos han despreciado, pero que muchos otros sí valoran poniendo su fe y su esfuerzo en ello.
La segunda mitad de mi vida será tan excitante...los numerosos momentos de felicidad que tendré destaparán mis conductos adormecidos, y un nuevo acuerdo con el mundo restaurará la confianza en mi alma dando otra vez intensidad a mis sentidos. Pero ahora con un poco más de sabiduría.
Un fascinante abrazo.
Al González.
jueves 24 de julio de 2008
Reunión de colegas Delphi en Ciudad de México
Hace algunas semanas Antonio Castillo, uno de los desarrolladores Delphi y Oracle más reconocidos de Guatemala y del mundo de habla hispana, viajó a El Cairo, Egipto para entregar el desarrollo de un sistema de software a un cliente de aquel místico país africano.
A su regreso estará unas horas en Madrid la mañana del sábado (españoles: todos al AVE ;)) y posteriormente hará otra escala en Ciudad de México para participar en una interesante reunión de colegas Delphi que se llevará a cabo en un popular restaurante este lunes 28 de julio.
En octubre del año anterior tuve oportunidad de conocerlo en persona y desayunamos en ese mismo lugar junto con otros colegas, como aperitivo del evento que organizó CodeGear para presentar Delphi 2007.
Esta vez, varios colegas y buenos amigos de Ciudad de México invitan a una quedada Delphi en el Restaurante VIPs de Avenida Insurgentes y Reforma (cerca de la estación del metro Insurgentes). Antonio será el invitado de honor por venir del extranjero y por lo que representa su trayectoria para las comunidades de programadores. Hay un personaje extranjero más de cierto calibre, que casualmente se encuentra en México también y podría asistir a dicha reunión, pero omitiré su nombre hasta que confirme si tendrá oportunidad de allegarse a la cita.
Para quienes nunca han participado en una reunión presencial de colegas Delphi, les dejo este enlace de hace cuatro años que les ayudará a imaginar lo bien que lo pasa uno:
http://groups.msn.com/ce77cj5fut58ai6vahamsb3nb1/interfazgh.msnw?action=get_message&mview=1&ID_Message=1916&all_topics=1
Aquella fue la primera reunión auspiciada por miembros de la comunidad Delphi mexicana. En esta nueva ocasión habrá exposición planeada de interesantes temas técnicos y estarán presentes algunos de los miembros más activos de Club Delphi.
Tenía toda la disposición de coincidir con Antonio y otros amigos en esta reunión, pero me encuentro a casi dos mil kilómetros atendiendo el llamado de un cliente y temo que no dispondré del tiempo necesario para viajar al Distrito Federal. No obstante me siento motivado para publicar este anuncio e invito a todos mis lectores cercanos a la capital del país a asistir al encuentro. No pierdan la oportunidad de convivir con otros colegas Delphi y de intercambiar útiles conocimientos y experiencias de vida. Quienes ya lo hemos hecho descubrimos por qué Delphi es más que un lenguaje de programación.
Pocas tecnologías propician que sus usuarios enriquezcan su pensamiento y forma de ver el mundo. Delphi es una de ellas gracias a la sólida formación de sus más destacados exponentes.
No lo olviden, Ciudad de México, lunes 28 de julio, 6:00 PM, restaurante VIPs de avenida Insurgentes y Reforma (cerca del metro Insurgentes). Para mayores informes envíen un mensaje privado a Poliburro a través de su perfil en Club Delphi o su perfil en PDM.
¡Mucho éxito! Un abrazo entre colegas.
Al González.
sábado 7 de junio de 2008
California 1 – Washington 0
Con mucho gusto los saludo después de los tres días que pasé en Ciudad de México impartiendo el curso de Firebird con dbExpress. Participó todo el equipo de desarrollo de la casa de software que me contrató, dándome cálidas muestras de agradecimiento por el conocimiento que compartí en su sala de proyecciones. Creo que jamás había tratado presencialmente con un grupo tan experimentado, numeroso y cohesionado de colegas Delphi. En ninguno observé pizca alguna de “fundamentalismo informático”, sólo vi mentes abiertas y positivas. Jorge y sus muchachos han logrado consolidar un gran equipo de trabajo. Es claro cómo es que Delphi los ha llevado a la posición que tienen como compañía de paquetería comercial.
Además de dbExpress, aumentaron sus nociones sobre TDataSetProvider y TClientDataSet, y se convencieron de la importancia de utilizar algo como Magia Data en los desarrollos. Después de la demostración de ayer, la tercera venta de esta suite de componentes se dio sin mayores preámbulos. La gran cantidad de trabajo que simplifica hace agua en la boca de quienes la miran andar, apartando modestia. Al final me han pedido que les envíe una propuesta económica para ser su asesor en uno de los proyectos que comienzan. Ya les comentaré algo al respecto en caso de que lleguemos a un buen acuerdo. :)
¿Quién quiere "hacer mejor" a Visual Studio?
Cambiando de tema, quiero hacer una denuncia legítima contra la empresa que fabrica Visual Studio. Esta tarde, mientras ayudaba a un colega y conocido forista de Club Delphi con un asunto de visibilidad de propiedades, ingresé a la ayuda de Delphi 2007 para realizar una consulta y me vi sorprendido por un repentino icono en la barra de tareas que mostró un descarado globo de mensaje que rezaba «Help make Visual Studio better» (Ayuda a hacer mejor a Visual Studio). Aún después de cerrar la ayuda, el icono color naranja con amarillo permanece visible mientras RAD Studio esté abierto. Cabe mencionar que NO tengo instalado Visual Studio en mi computadora, y, al pasar el ratón encima de dicho icono, éste todavía se atreve a mostrar su hinchado nombre: “Visual Studio Customer Experience Improvement Program”.
Y he aquí la interfaz de usuario de ese desagradable programa espía —típico de Microsoft, una fuente de texto insalubre (demasiado pequeña)—:
Empleando Google, encontré que se trata de algo programado a propósito en .NET 2.0. Incluso ya ha sido denunciado por otros colegas:
http://qc.codegear.com/wc/qcmain.aspx?d=43088
http://memyselfanddelphi.blogspot.com/2007_03_01_archive.html
Francamente da pena ajena ver a la empresa de Redmond recurriendo a jugarretas como esas. El mensaje bien puede interpretarse como: «Tememos que uses .NET con algo mejor que nuestro Visual Studio, ya que como el mismo .NET fue inventado por ingenieros que trabajaban en Borland, nos da cosa que vayas a preferir a RAD Studio». ¿A qué ejecutivo de Microsoft se le habrá ocurrido hacer que .NET cargara ese icono en pantalla, aún sin tener Visual Studio instalado? ¿Acaso pensaron que nadie se molestaría, que nadie interpretaría con un mínimo de inteligencia la sucia maniobra? ¿Y ese es el Visual Studio que dices que va muy bien, Ramiro? Yo prefiero la dignidad, la calidad y el honor que siguen caracterizando a nuestro Delphi.
En la sombra de este mal trago hay un poco de alegría, porque el abusivo monopolio tropieza una vez más con la misma bota que usa para intentar aplastar lo que le supera.
Un abrazo despertando conciencia y "haciendo mejor" al mundo entero.
Al González. :)
viernes 30 de mayo de 2008
¡Magia Data liberado!
Me siento muy contento porque la pequeña empresa de software que dirijo ha liberado este viernes 30 de mayo de 2008 la suite de componentes Magia Data que comencé a programar hace más de dos años.
Este es uno de los trabajos a los que mayor dedicación he entregado en mis 16 años de carrera. La constituyen seis componentes Delphi “extendidos” totalmente compatibles con sus versiones nativas, pero que ofrecen nuevas propiedades, métodos y eventos para hacerle la tarea más fácil a los programadores que trabajan con bases de datos.
No importa cuál sea el motor utilizado, estos componentes soportan las bases de datos más populares (incluyendo Firebird, por supuesto) y combinan perfectamente con otros componentes de acceso a datos que estemos acostumbrados a utilizar (ADO, IBX, BDE, etc.).
Tiene:
un DataSource clonador,
un ClientDataSet más dinámico,
un DataSetProvider cuántico,
un SQLConnection más humano,
un FirebirdSQLConnection cuyo nombre lo dice todo y
un SQLQuery buen padre de sus parámetros.
La página oficial del producto es: http://www.sistemasgh.com/magiadata.php. Ahí encontrarán una referencia completa de todas las nuevas características que brindan estos componentes derivados. Las demostraciones de Magia Data que he realizado en algunas ciudades han causado feliz admiración.
Les agradeceré todo comentario acerca de esta modesta suite de componentes que he desarrollado con pasión, empeño y como un pequeño aporte al fortalecimiento de Delphi. No dejen de leer la referencia, sospecho que se sentirán familiarizados con varios de los problemas que resuelve Magia Data. Como estos:
http://www.clubdelphi.com/foros/showthread.php?t=48173
http://www.clubdelphi.com/foros/showthread.php?t=50368
http://www.clubdelphi.com/foros/showthread.php?t=30633
http://www.clubdelphi.com/foros/showthread.php?t=46650
http://www.clubdelphi.com/foros/showthread.php?t=50563
Un abrazo mágico.
Al González. :)
lunes 26 de mayo de 2008
Resumen norteño
Atardecer del sábado 24 de mayo de 2008. En las cercanías de Torreón, a bordo de un autobús con destino a Zacatecas, donde pernoctaré antes de continuar el viaje de regreso Morelia. Después de dos completas e intensas semanas rescatando a Delphi en mi tierra natal.
Chihuahua está esplendorosa. Ya me hacía falta respirar ese aire limpio, apreciar los edificios del centro desde el barrio donde crecí, caminar por sus nuevas y armoniosas plazas dignas de cualquier ciudad europea, y, por supuesto, ver a mi familia.
Las calles tan limpias y ordenadas, aceras que invitan a andar cómodo y sin presiones, tanto al que camina como al que rueda sobre amables rampas. La urbanidad y el urbanismo plasmados en cada esquina y muy claros en la mente de quienes administran y ejecutan los servicios públicos. La gente, mi gente, feliz de vivir en esa ciudad de la Norteamérica mexicana, trabajando con ánimo cuando se debe y celebrando con alegría responsable cuando se puede. Hace más de cien años un pueblo ya viejo que gozaba de mucha energía y valor acordó instalar el bienestar en esa región, y muchos años después, ante la perversión de dicho establecimiento, una corriente política de izquierda no reaccionaria dejó firmemente asentada la cultura de la honestidad y la justicia social en sus habitantes. Fue así que se consolidó el espíritu chihuahuense.
Pero ni esto salva a mi ciudad maravilla de la poca inteligente guerra que el gobierno libra en el país entero en contra del tráfico ilegal de drogas. Hasta en Chihuahua se han presentado sanguinarias ejecuciones en los últimos meses.
El autobús acaba de pasar encima del río Nazas (el arenal donde alguna vez estuvo), o sea que hemos salido de Durango y entrado a Coahuila.
Llegué a Chihuahua la madrugada del 10 de mayo, famoso Día de las Madres en México. A la mía le había prometido desde agosto (cuando programaba el sistema de puntos de restauración CSP de Magia Data) que iría a visitarla pronto. No me fue posible entonces, ni tampoco en las fiestas de fin de año. Pero no dejaría pasar esta primavera sin venir a ver a mis ancianos padres y casados hermanos. Trabajé en casa ese y los siguientes días, improvisando un modesto estudio en el cuarto de los tiliches que a la vez me sirvió de dormitorio.
El martes 13 comí con Luis, quien fue mi pupilo allá por el año 2000, y a quien no veía desde hace casi cuatro años. Recuerdo el día que con solo 17 años de edad acudió a mi tétrica oficina de la calle Segunda para solicitar trabajo de programador y muchas de las buenas horas que pasé enseñándole a desarrollar con Delphi. Hoy trabaja con sistemas ERP en una de las compañías cementeras más grandes del mundo. El año pasado lo enviaron a Bolivia, donde conoció en persona al buen Onti, conocido forista que también defiende a Delphi a capa y espada en su país.
El miércoles me llamaron de una casa de software localizada en Ciudad de México. Se encuentran en un punto crucial de su vida como empresa fabricante de paquetería comercial. Tienen millones de líneas de código que han escrito en Delphi desde hace años, código con el cual han construido muy útiles aplicaciones algo conocidas en México. La finalidad es ayudarles en su transición de Paradox a cliente-servidor, algo que desde hace un lustro viene dándose con todos los desarrolladores Delphi que empezamos usando bases de datos de escritorio. Me hicieron hablar en conferencia telefónica ante su equipo de desarrolladores a quienes comenté algunas de las vicisitudes y oportunidades de este objetivo. Al cabo de unos días me comunicaron que aceptaban contratar los servicios de Sistemas GH. Realmente me siento feliz por este importante reto. El 4 de junio iniciaremos con un breve curso de introducción a dbExpress con Firebird, donde mostraré algunas de las ventajas de Magia Data y del resto de nuestro framework. Al parecer ya están convencidos de que DBX es el conducto de bases de datos más certero dentro de Delphi, así que espero no sea difícil convencerlos de usar mis componentes DBX extendidos también. Adicionalmente, decidieron adquirir el viejo pero todavía útil curso “empaquetado” de Firebird con IBX.
Al día siguiente asesoré a Fernando en el uso del componente gratuito para huellas digitales GH FingReader y de Magia Data, suite que compró ese mismo día. Él colaboró conmigo en Morelia hace poco más de dos años durante una breve estancia de tres meses. Le tocó entonces conocer los inicios de estos componentes extendidos, cuando un servidor comenzaba a conocer dbExpress y el famoso Client Data Set del que todo mundo hablaba ya. Un día descubrí que un componente TClientDataSet nativo no puede conectarse a un TDataSetProvider del mismo proyecto si no se encuentran los dos en el mismo módulo de datos. La limitación se justifica con el razonamiento de que este binomio de componentes debe emplearse en un esquema multicapa, o en un proyecto tan sencillo que no amerite emplear más de un módulo de datos. Pero entonces nosotros teníamos la idea de que debería existir un justo medio (como para todo en la vida) entre una típica aplicación de dos capas (interfaz cliente--servidor de base de datos) y una de tres (interfaz cliente--servidor de aplicaciones--servidor de base de datos). Queríamos establecer un esquema que nos permitiera desarrollar aplicaciones cliente-servidor sin complicaciones multicapa que en las primeras versiones de un sistema suelen ser innecesarias, pero de tal manera que la estructura Delphi de tales proyectos estuviese preparada para ser partida por la mitad en el futuro, cual dos hojas de impresión de formato continuo.
A este esquema le llamamos 2.5 capas; aplicaciones ahorrativas como cualquiera de dos capas, pero preparadas para pasarse a tres cuando el proyecto en cuestión lo amerite. Esto volvía necesario colocar los conjuntos de datos clientes en un módulo de datos y sus respectivos proveedores en otro para poder marcar la línea de corte entre las dos hojas. Por ello agregué a TMagiaClientDataSet la propiedad Provider, con la cual podemos asociar el conjunto de datos con cualquier TDataSetProvider del proyecto, independientemente del módulo de datos donde se localice éste. Resultó ser una buena alternativa a la propiedad ProviderName. Aún recuerdo la admiración del entonces novato Fer, cuando le mostré el funcionamiento de esa nueva característica. Eran grandes tiempos, yo acababa de conocer a Janett, el changarro tenía ingresos estables, no le debíamos dinero a nadie y no estábamos atrasados en ningún proyecto. Hoy es muy diferente.
El viernes 16, una amiga de Saltillo me pasó el dato de que una empresa mediana pero bastante dinámica (por lo que pude inferir después) necesitada de servicios de programación en Delphi. Después de varias llamadas y correos, la mañana de hoy se comunicaron a Morelia para solicitar una entrevista presencial en la capital de Coahuila. Me hubiera gustado disponer de algo más de tiempo para tomar el autobús a Saltillo y no a Zacatecas, pero dado que no quiero descuidar compromisos adquiridos anteriormente, tal visita a Saltillo tendrá que esperar unas semanas. En el peor de los casos, si nos vemos sobrepasados en trabajo buscaré a alguien de confianza y comprobado nivel de servicio que le interese atender este caso. Esto me deja pensando en que nos caería de maravilla, en esta época de nuestra historia como empresa, un inversionista inteligente y honrado que quiera apoyarnos ahora que estamos teniendo francas y buenas oportunidades de negocios. Estamos dejando correr mucho agua, de la que ciertamente no podemos beber, pero sé que podremos beberla cuando contemos con un poco más de recursos.
El lunes siguiente vi a Mario en su oficina del Colegio de Bachilleres, un antiguo cliente que hace tiempo adquirió el curso empaquetado de POO, pero a quien todavía no tenía el gusto de conocer en persona. Se comprometió a promover nuestros cursos y talleres ante los directivos de la institución donde trabaja, y personalmente adquirió esta vez el viejo curso de Firebird. Al principio me observaba con un semblante tenso, pero le dije «¡Hey viejo! No me veas como a un extraño, soy tan chihuahuense como tú, sólo que ya llevo varios años viviendo fuera». Por la ventana de su oficina podía apreciarse la bella claridad del cielo, distinguiéndose sin problemas limpios edificios y jardines lejanos. Vistas que hacen posible estar contento.
Por la tarde de ese día le llamé a Moisés para preguntarle dónde podía verlo para la clase de programación que me solicitó. Como Fernando, trabaja en el gobierno de Chihuahua, a dos edificios de distancia. Es un joven colega Delphi que tengo en mis contactos del mensajero desde hace varios años pero que, al igual que Mario, no había tratado hasta ese día presencialmente. Para sorpresa de ambos, resultó que vive a doscientos metros de la casa de mis padres (¡vaya que el mundo es pequeño!). Entre otras cosas, viendo su código, le hice hincapié en que no debe emplear constantes literales (1, 2, 3...) para indicar opciones de programa, le expliqué la ventaja de usar en su lugar tipos enumerados (opAlta, opBaja, opCambio...).
El miércoles 21 y el jueves 22 la familia les hizo un pequeño festejo a mi hermano menor y papá por sus respectivos cumpleaños. La verdad que ya extrañaba comer en casa junto a mis familiares y compartir los últimos sucesos de nuestras historias de vida. ¡Que bueno es convivir con ellos! Comiendo pollo asado al carbón, ahí, en la misma casa de adobe y piedra donde jugábamos los hijos cuando éramos pequeños, atizando la sobremesa con cada graciosa ocurrencia del ingenio fraternal, mientras los sobrinos desarrollan un armonioso caos en otra habitación.
Ese jueves por la tarde fue Moisés a casa para la segunda clase. Esta vez vimos algo de POO. Observando el código fuente de la VCL, repasamos las bases de herencia, encapsulamiento y polimorfismo, además de explicar cómo funcionan los métodos virtuales. Creamos una clase de ejemplo TXButton, derivada de TButton, y aproveché para enseñarle el viejo pero útil truco del molde de acceso, que nos sirve para hacer referencia a elementos protegidos de una clase, a los cuales el compilador no deja acceder libremente. Al despedirnos compartió conmigo estas insólitas palabras: «En el trabajo les dije que vine a clase contigo, pero no me creyeron, mucho menos cuando les comenté que eres mi vecino».
El viernes 23 tuve una reunión más en el mismo edificio donde trabaja Fernando, pero tres pisos más arriba. Vi a un activo funcionario (esas dos palabras sí pueden ir juntas) que ha desarrollado en Delphi mucho del buen software que tiene el gobierno estatal, llamándome la atención un sistema GIS con el que pueden saber todo acerca de cualquier edificio o terreno de la ciudad, observando su posición desde una vista satelital que remarca y titula las calles aledañas (aclarando que se ve mucho mejor que el mostrado por Wikipedia). Además desarrolló un software catastral que ya no sólo se utiliza en la administración pública de Chihuahua, sino que además ha “exportado” a otras provincias por su efectividad intrínseca. Quiere que Sistemas GH le de seguimiento y mejora a ese sistema en ciertos municipios del país. Y se mostró interesado en que yo vuelva pronto a Chihuahua para dar cursos y consultorías Delphi a personal y áreas de su influencia.
Y entre todo esto, conocer a Ilse y convivir con ella en varias ocasiones, fue una de las mejores y más intensas cosas que pudo pasarme en este viaje.
Un rico burrito de lomo trae buena suerte.
Al González. :)
lunes 5 de mayo de 2008
Resumen tapatío
A bordo del autobús, regresando a Morelia después de dos interesantes semanas en Guadalajara. Ha valido mucho la pena dejar ese entelarañado apartamento donde vivía. Creo que a veces es necesario dejar de tener casa para atreverse a salir de las estrechas fronteras de una ciudad y respirar algo de libertad.
Estando en Guadalajara sucedieron muchas cosas interesantes. Desde que llegué me puse en contacto con todos los colegas Delphi de Jalisco que conozco, foristas de Club Delphi y PDM. A algunos como Norberto y Ramiro ya tenía el gusto de tratarlos en persona, y esta vez tuve el privilegio de conocer y estrechar la mano de varios otros como Paoti, Salvador, Esteban y Gabriela. Desafortunadamente no fue posible conocer en persona en esta ocasión a Omar, Isaac y Ulices (sí, Ulises con ce), éste último uno de mis más antiguos y allegados contactos en el mensajero.
Ramiro, a quien no veía desde hace un año, fue el primero que estuvo disponible. Le mostré grosso modo el framework que hemos construido en Sistemas GH, resultándome muy emotivo notar su admiración ante dos sencillas pero poderosas propiedades que hemos agregado al componente DataSource: DataSetCloned y DataSetEvents. La capacidad de clonar objetos data sets en tiempo de ejecución y la de utilizar, de manera particular en cada formulario, los eventos de un data set colocado en un módulo de datos fue lo que más les llamó la atención a él, y posteriormente a Norberto y Esteban. Incluso este último decidió comprar una copia de Magia Data para Delphi 7 después de la asesoría que le di. Ramiro también mostró interés en comprar la suite Magia Data, pero se esperará a que tenga lista la versión para Delphi 2007 dentro de algunas semanas.
Algo que llamó mucho mi atención es la combinación tan especial que se da en Guadalajara de una vigorosa actividad económica e industrial y la gran pasión con que sus numerosos programadores Delphi aprecian y defienden a este respetado lenguaje de programación. Guadalajara es sencillamente una de las ciudades con mayor corazón pascalero de México. Creo que CodeGear y sus distribuidores deberían sacarle mayor provecho a esta estupenda sinergia jalisciense.
Conocí un poco la bella y famosa zona de Tlaquepaque gracias a Esteban, quien toda su vida ha residido ahí, y a quien desde el año anterior hemos estado asistiendo en su transición al mundo cliente-servidor, primero a través del mensajero y ahora presencialmente. En estos días aprendió muchos conceptos que no tenia del todo claros y comprendió varias de las vicisitudes que deben tenerse en cuenta en este paradigma de bases de datos. Esclarecimos que el uso de bases de datos cliente-servidor no significa que deba escribir cientos de sentencias SQL Insert Into, Update y Delete; el temeroso mito por el cual muchos desarrolladores demoramos varios años en ingresar a este obligado terreno. Le mostré lo fácil que es acceder a una base de datos Firebird local o remota con dbExpress y TClientDataSet, y le expliqué la razón por la cual se necesita un TDataSetProvider como auxiliar y las ventajas de usar un conjunto de datos de memoria. Cuando terminamos el programa de ejemplo, logrando transferir información de un par de tablas Paradox locales a una base de datos Firebird remota mediante dirección IP y alias, me dijo alegremente sorprendido: «¡No sabes cuánto tiempo esperé para ver esto!». Como asesor, fue para mí una gran satisfacción, de esas que reafirman porqué es tan bueno enseñar a otros.
Lamentablemente no me fue posible presenciar los eventos en línea del lunes 21 y martes 22 de abril. Tras algunos amables correos que intercambié con Gopac antes de partir a Guadalajara, y la intención de ambas partes de entrevistarnos, asumí que me dejarían conectarme en sus instalaciones y de paso ver asuntos para los que pudiera ayudarles con el fin de generar mayor cohesión y sinergia entre CodeGear y los programadores Delphi. Pero supongo se les complicó de algún modo, así que me quedé esperando confirmación sin poder ver los eventos. Eso sí, le encargué a Cheché que estuviera muy atento en Morelia a las ponencias para valorar todas las buenas cosas nuevas que han añadido a los productos. Sobre todo me interesa estar al día con Delphi Win32 y adquirir todas las actualizaciones que lancen de Delphi for PHP.
En compensación, el jueves 24 sucedió algo verdaderamente extraordinario, algo de lo que no debo estar nada orgulloso, pero que le dio un positivo giro de 179 grados a un tremendo problema que venía acarreando desde el año pasado. Como algunos saben, estuve a punto de ser demandado por la empresa de mi principal cliente en el D.F. debido a retrasos en un importante proyecto de software. La empresa ya canceló definitivamente el proyecto, y es SAP quien está haciéndose cargo ahora de ese complejo caso. Pero ha sido él, como socio y director de su empresa, quien hizo frente a los inversionistas cubriéndome la espalda una vez más. Se hizo responsable por el importe hasta ahora pagado, el cual sé, porque conozco sus circunstancias, no le será fácil cubrir. Por mi parte, el compromiso es terminar el proyecto más o menos como se tenía pensado, agregando ciertos módulos.
La piedra angular de esto es que se ha trabajado tanto en este sistema, que sería absurdo tirarlo todo por la borda. Así que el proyecto continúa, con otro nombre y para otra entidad fiscal, pero continúa. Lo terminaremos y mi cliente hará un uso que considero muy inteligente, redituable y estratégico del mismo. Por fin encontramos salida a la espantosa ecuación en que nos habíamos metido. De momento no habrá más inversión directa para ese proyecto hasta comenzar a obtener los resultados esperados, será difícil sostenerlo a base de utilidades obtenidas en otros rubros, pero no imposible. Al final todo habrá valido la pena y podremos trabajar en muchas más soluciones de software que el cliente ya visualiza con nosotros. Yo nunca quise soltar este proyecto porque es muy interesante todo lo que estamos haciendo en él. Con esto que sucedió ahora hemos entrado a un camino más sano, lógico y transitable y se me ha quitado un enorme peso de encima. Siento que con esto la mitad de mis problemas encuentran resolución, y tengo la extraña impresión de que el desenlace hubiese sido distinto de no haber ido a pasar unos días en Guadalajara.
Al día siguiente, el viernes 25, me invitaron a una tertulia de colegas en el Sanborns de Avenida Vallarta, el mismo donde conocí a Ramiro hace un año. Fue muy grato ver ahí a Norberto y conocer en persona a Salvador y Álvaro. Me he dado cuenta que cada vez es más común encontrar programadores en los restaurantes, aprovechando la señal abierta de Internet y socializando más. Desaparece el estereotipo del desarrollador solitario, ensimismado, aislado del mundo en una habitación. Empieza a notarse esta tendencia. Incluso hoy, durante la asesoría que le di a Estaban en uno de esos restaurantes, advertimos que en la mesa contigua estaban otro par de desarrolladores trabajando en una laptop y hablando sobre lenguajes de programación.
El sábado 26 tuvimos una segunda reunión, donde Norberto por fin pudo conocer las mejoras que hemos implementado con Magia Data y las plantillas de herencia visual de nuestro framework. Va a ser muy gratificante para los que formamos parte de Sistemas GH ver a otros desarrolladores utilizando estos componentes que con tanto esfuerzo y dedicación he desarrollado. Por lo pronto la primera venta de éstos se cerró hoy, esperemos que vengan muchas más.
Cuando no tenía reunión, mis sesiones de trabajo se desarrollaban principalmente en el comedor de mi cuñada. Es una pena que mi hermano mayor tenga menos atenciones conmigo que su propia esposa. Él ni siquiera tiene idea de qué estoy haciendo actualmente, de cuáles son mis circunstancias actuales, mis logros y mis metas, apenas si sabe que tengo una pequeña oficina en Morelia, pero no se interesa en nada que no sea su propia carrera profesional. No recuerdo ninguna pregunta seria y de interés que me haya hecho desde que terminé la escuela secundaria. Es como si simplemente me hubiese borrado de su vida, y no tengo idea de cómo es que aún así me dio alojamiento en su casa. Esta noche hizo el favor de acercarme en su auto a la terminal de autobuses, durante el camino no paró de lanzar maldiciones y palabrotas, acusando a mis padres sin su presencia de no haberme “educado como debe ser”. A veces me pregunto en qué momento mi hermano perdió el piso y se volvió un amargado egocéntrico empedernido.
Pero una de las mejores cosas de esta estancia en Guadalajara es haber conocido a Gabriela, una chica de los foros que no sólo es experimentada en Delphi, sino además muy simpática. Es una de esas muchachas auténticas, de las pocas que suelen verse hoy día, sin tapujos para hablar y expresar lo que siente y con una muy atenta manera de escuchar a las personas. Habla muy bien de varios de los compañeros de Club Delphi, a más de diez nos tiene perfectamente identificados. Jhonny fue su “iniciador”. Por cierto, este lunes 5 será su cumpleaños.
Mis quince jornadas en GDL. Ahora pernoctaré unos días en la oficina de Morelia y luego iré a visitar a mis padres y demás hermanos en Chihuahua, y a varios amigos de esa ciudad. Espero tener la opción de regresar vía Los Mochis para visitar a AGAG4 y su pandilla de buenos pascaleros y foristas Delphi. Después, durante este mismo mes, es probable que vaya a Cuernavaca a dar un taller (sólo estoy esperando una llamada de la persona que me externó su interés hace unos días).
Un abrazo tapatío.
Al González. :)
viernes 11 de abril de 2008
Dejo Morelia (por un tiempito, no se asusten)
Espero les haya resultado interesante el tema de los objetos superglobales. En esta ocasión seré breve.
Primero que nada quiero invitar a todos los desarrolladores Delphi y demás colegas allegados a esta noble y potente herramienta de programación a participar en el próximo evento en línea que CodeGear ofrecerá los días lunes 21 y martes 22 de abril.
Recuerden que estos eventos no llevan costo alguno y pueden seguirse desde cualquier lugar del mundo. Además le permiten a uno conocer a otros desarrolladores Delphi, intercambiar opiniones en ventanas de conversación privadas e incluso proponer acuerdos de trabajo o negocios entre desarrolladores, muchas veces de la misma ciudad.
Desde mi punto de vista, ninguna empresa que use Delphi como herramienta de programación (ya en regla o todavía sin licencia) debe quedarse fuera de este tipo de eventos. También es una buena oportunidad para promoverse y acercarse a los distribuidores locales de Delphi y capacitaciones (o hacerse de los servicios de un instructor no convencional como yo ;)).
No obstante, lo más importante son las ponencias técnicas (que cada vez resultan mejores) de experimentados desarrolladores Delphi. Varios de ellos reconocidos foristas y autores de bitácoras.
Para ver los temas que se expondrán y registrarse, entren a esta página (descuiden, no tiene virus :p): http://dn.codegear.com/article/37847
Espero ver muchos nombres conocidos ahí, y por favor que alguien les avise a los de Chihuahua. Extraño ver colegas Delphi de mi tierra natal. :)
Punto y aparte.
El otro asunto es que la semana entrante dejaré el apartamento donde he vivido durante casi dos años y medio en Morelia. La oficina se mantiene, con turbulencias aún, y seguimos construyendo orgulloso software. Soy solo yo quien me moveré a Guadalajara por un par de semanas para empezar, y luego otro par de semanas a Chihuahua. Por uno o dos meses estaré alojándome en casa de familiares y amigos para:
1. Despejar la mente.
2. Concentrarme en la parte técnica de mi trabajo.
3. Ahorrar dinero.
Soy de esos tipos que necesitan viajar para recargar las baterías y avanzar en su trabajo sin comenzar a creer que vive en Matrix.
Durante este tiempo, si alguien necesita asesoría, capacitación o asistencia en programación en Delphi, dentro de territorio mexicano, siéntase con toda libertad de invitarme a pasar unos días en su ciudad para compartir código, aprender más sobre desarrollo y seguir rescatando a Delphi (algonzalez74 [arroba] hotmail [punto] com).
Les doy el teléfono de la oficina para lo que se ofrezca: 01 443 327-3361
Un abrazo en línea o presencial.
Al González. :)
lunes 3 de marzo de 2008
Objetos superglobales. Memoria compartida como nunca antes.
¡Hola!
Antes que nada les comento que estaré este lunes 3 de marzo en Ciudad de México. El plan es regresar Morelia por la noche, a no ser que surja algún llamado para dar un taller o asesoría Delphi, o alguna invitación para permanecer ahí o ir a otra ciudad por unos días. Ya saben que con portátil y sin mujer uno puede moverse a donde lo inviten (aunque sería maravilloso tener una mujer consorte de mis aventuras).
Por fin me doy un poco de tiempo para hablar del tema que les había prometido: Memoria compartida en forma de objetos “superglobales”.
Para empezar es conveniente dar un poco de contexto:
En diciembre de 2003 estuve investigando sobre diferentes formas en que dos aplicaciones Windows en ejecución, es decir, dos procesos, pueden intercambiar datos en tiempo real. Encontré un interesante mecanismo llamado Named Shared Memory o Memoria Compartida con Nombre en un artículo de MSDN (la más vasta y útil referencia acerca de las APIs de Microsoft) similar a este: http://msdn2.microsoft.com/en-us/library/aa366551(VS.85).aspx
Como ya entonces era común en mí usar funciones de la API de Windows para resolver diversos problemas de programación, supe que no me resultaría difícil implementar lo que buscaba. Sólo tenía que estudiar y emplear las funciones CreateFileMapping y MapViewOfFile como lo indicaba uno de los ejemplos de MSDN. Para ello me apoyé también en el sagrado archivo Win32.hlp que, bendita Providencia, acompaña a todo Delphi; un fastuoso archivo de ayuda donde he realizado cientos de consultas fructíferas. En él vienen muy bien explicadas la gran mayoría de las funciones de la API Win32. Es uno de esos archivos de ayuda que se crearon sin prisas, concienzudamente, como fueron creados también los valiosos y extensos archivos de ayuda del propio Delphi en la época en que Microsoft era informativamente justo y Borland una empresa sumamente venerada y con más recursos económicos para documentar debidamente sus herramientas (como lo volverá a ser en pocos años).
Y aquello funcionaba. Utilizando dichas funciones logré que dos de mis aplicaciones Delphi en ejecución intercambiaran datos de una manera muy transparente. Una escribía bytes en un buffer, y la otra podía leerlos sin más, como por arte de magia. No me extenderé hablando de cómo trabajan estas dos funciones, sobre eso ya hay bastante material en Internet y en Win32.hlp mucho mejor explicado de lo que yo podría tratar.
Pero si es conveniente mencionar que CreateFileMapping se utiliza para crear o abrir un objeto de mapeo de archivo (file mapping object) —algunos autores les llaman “proyecciones”, pero no estoy seguro de usar ese término—, el cual puede ser compartido entre procesos. La función se aplica sobre un identificador de archivo (file handle) que previamente hayamos abierto o creado y nos regresa un identificador de un objeto que nos permite controlar vistas o “mapas” de diferentes secciones del archivo, sobre las cuales podemos hacer lectura o escritura de bytes. MapViewOfFile es la función que nos permite definir dichas vistas. Al llamarla le damos el identificador obtenido con CreateFileMapping, la posición del archivo a partir de la cual queremos que la vista tenga acceso y la cantidad de bytes disponibles para “ver”. La función nos regresa un puntero al primer byte de memoria de la vista; si escribimos en ese buffer, estaremos escribiendo en el archivo, y si leemos, estaremos leyendo lo que el archivo contiene en esa sección.
Así pues, CreateFileMapping se utiliza para crear un objeto de mapeo “controlador de vistas” sobre un archivo y MapViewOfFile para abrir en sí cada vista o “ventana”. Es como si el archivo fuese una caja de cartón llena de pelotas de tenis (sus bytes), las vistas pequeños recortes que hacemos en sus paredes para tomar dichas pelotas o introducir otras, y el objeto de mapeo es el encargado de todas esas ventanas por las cuales se accede al contenido del archivo. Pudiendo dicho objeto de mapeo ser compartido entre diferentes programas en ejecución.
Estas son las cabeceras nativas y sus correspondientes versiones Delphi de dichas funciones:
-----------------------------------------
HANDLE CreateFileMapping(
HANDLE hFile, // handle to file to map LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes DWORD flProtect, // protection for mapping object DWORD dwMaximumSizeHigh, // high-order 32 bits of object size DWORD dwMaximumSizeLow, // low-order 32 bits of object size LPCTSTR lpName // name of file-mapping object
);
function CreateFileMapping(hFile: THandle; lpFileMappingAttributes: PSecurityAttributes;
flProtect, dwMaximumSizeHigh, dwMaximumSizeLow: DWORD; lpName: PChar): THandle; stdcall;
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // file-mapping object to map into address space
DWORD dwDesiredAccess, // access mode
DWORD dwFileOffsetHigh, // high-order 32 bits of file offset
DWORD dwFileOffsetLow, // low-order 32 bits of file offset
DWORD dwNumberOfBytesToMap // number of bytes to map
);
function MapViewOfFile(hFileMappingObject: THandle; dwDesiredAccess: DWORD;
dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap: DWORD): Pointer; stdcall;
-----------------------------------------
Pero hasta aquí se habla solamente de archivos, y esta entrada tiene que ver con compartir memoria entre procesos. Pues bien, la clave para crear memoria compartida es llamar a CreateFileMapping con un parámetro inicial de Invalid_Handle_Value, el cual no es un identificador válido de archivo. CreateFileMapping toma esta constante como indicador de que debe crear el objeto de mapeo sobre el famoso archivo de paginación (o archivo de intercambio) del sistema operativo. Al ser este archivo “memoria RAM virtual”, usar una parte de él para intercambiar datos entre programas es, en la práctica, lo mismo que sería usar un buffer de RAM para el mismo propósito (imaginando que Windows permitiese acceder a la RAM libremente). Aunque tengo mis dudas de si realmente se graba en disco algo que escribimos en una vista mapeada de este tipo, tal vez el sistema operativo mantiene estas vistas especiales en ágil RAM real; la verdad ignoro cómo Windows maneja estos casos. Pero pues ¡qué bonito! Con CreateFileMapping e Invalid_Handle_Value reservo un bloque de memoria, al que le doy un nombre por el cual otros procesos pueden emplear ese mismo bloque, y con MapViewOfFile creo accesos al mismo.
Sin embargo, como programador bibliotecario que soy, me planteé encapsular el uso de estas dos funciones en una clase o componente Delphi, bajo un nombre como "TMemoriaCompartida". Buscando en la Red, descubrí que varios autores ya habían creado soluciones similares a mi idea inicial. Hoy en día pueden verse muchas clases llamadas "TSharedMemory" que cumplen con el propósito. Por lo general, dichas clases ofrecen algún tipo de propiedad o función de tipo puntero para acceder al bloque de memoria compartida, y para escribir en ese buffer suelen emplearse métodos tipo WriteXXX/SetXXX. Pero a finales de 2003, cuando me encontraba sumergido en todo este proceso de análisis y después de haber visto el código fuente de varias de las clases escritas hasta el momento, tuve una reflexión que en un lenguaje de programación diferente a Delphi probablemente se hubiese hundido en el mar de las utopías:
«Sería interesante que la propia instancia del objeto de memoria compartida fuese la memoria compartida en sí».
Después de decirme esto, automáticamente mi cerebro revisó algunos viejos recuerdos de mis primeras indagaciones sobre la clase TObject (ancestro de todas las clases) y...¡lotería!
«¡Pero claro, TObject tiene un método virtual que le permite a uno definir dónde y cómo asignar la memoria de la instancia!»
Ese método virtual tiene por nombre NewInstance, es un método clase que es llamado cada vez que se realiza una instanciación de objeto. Una instrucción como TMiClase.Create causa una llamada inicial al método NewInstance para reservar la memoria que requerirá el objeto, y como este método es virtual, podemos redefinirlo en TMiClase para hacer que la memoria del objeto se asigne de manera distinta a lo normal.
La gran ayuda de Delphi es clara al respecto:
Override NewInstance only for special memory allocation requirements.
[Redefina NewInstance solo por requerimientos de asignación de memoria especiales.]
Fue así que escribí una clase de memoria compartida muy sui géneris, la cual incluí en mi biblioteca de clases y funciones. Hace unos días la desempolvé, afiné, renombré como TSuperGlobalObject y la publiqué en Club Delphi:
Código fuente explicado y descarga.
Los invito a descargar la unidad y probarla creando una clase derivada de TSuperGlobalObject. En un programa en ejecución podrán hacer algo como
MiObjetoCompartido.Campo := Valor;
Y en otro programa en ejecución (que puede ser o no instancia del mismo ejecutable) leer el contenido de ese objeto:
X := MiObjetoCompartido.Campo;
Todos los campos que definamos en nuestra nueva clase serán alojados en la propia memoria compartida. Con esta solución, el acceso a la memoria compartida encapsulada en un objeto Delphi se hace de manera totalmente natural y transparente desde cualquier proceso. Y por eso les he llamado objetos superglobales.
Sólo aclarar que por la naturaleza tan especial de estas clases de objeto, debemos tener muy en cuenta las tres restricciones que enumero en uno de los comentarios del código fuente. Si las respetamos, tendremos una solución Delphi de memoria compartida muy práctica y accesible.
Espero les sea de utilidad a la hora de compartir datos entre procesos. Todas las preguntas y sugerencias al respecto serán bien recibidas.
Un abrazo superglobal.
Al González. :)