25 oct 2017

El secreto de la felicidad…

Ya tengo mis años en estas andanzas, me quedan dos años para alcanzar mi 40va primavera (aunque también he tenido inviernos), son casi 17 años de vida profesional, y desde que comencé este camino he tenido claro una cosa que, muy honestamente y sin tratar de engañarme a mismo (más de una vez me he sorprendido tratando de engañarme), ha logrado mantenerme feliz: Hago lo que me gusta hacer, simple y llanamente.

Desde muy temprana edad, en la época de chiquillo de escuela, conocí las computadoras. Aquellos cajones con letras en verde chillón o ámbar en fondo negro, me cautivaron, me enamoraron desde el principio. Unos cursos gratuitos de Logo y Logowriter que vinieron a ofrecer del Liceo León Cortés Castro (Grecia, Alajuela, Costa Rica) a mi escuela rural de distrito, fueron el disparo de salida para sumergirme en lo que iba a ser el resto de mi vida…

Había que ir y venir en autobús, en tiempo fuera de horario escolar. Para un niño sumamente tímido y retraído aquello era todo un reto, casi una hazaña;  pero ver moverse aquella tortuguita digital formando figuras a partir de los comandos que yo creaba, bien valían la pena: aquello me hacia feliz.

Computadora no había en casa, con mucho costo había un televisor a blanco y negro y un atún para repartir entre cinco más algo de arroz y frijoles. En esa época era impensable contar con una. Pero yo sabía que, tarde o temprano, me iba a dedicar a trabajar con computadoras sí o sí.

Un amigo, de más musculo económico, adquirió una. Aquella era una maravilla, no solo tenía verde, sino hasta 8 colores ¡8 colores! No existía nada en el mundo mejor que jugar Test Drive. Pasaba cada vez que podía, y, aunque los turnos para usarla eran largos, yo era feliz.

Llegué al colegio, al mismo liceo de los cursos, y salvo un brevísimo periodo de coqueteo con la biología (en parte por culpa de una joven y bonita profesora sustituta) mi ruta era clara, estar cerca del laboratorio de informática y llevar computación como materia técnica. Me gustaba mucho aprender, no únicamente de computadoras, y mientras aprendía era feliz.

Llegué a la universidad decido a estudiar informática, aunque no tuviera “machete” o herramienta. Pero mi padre y madre, quiénes con mucho esfuerzo habían logrado hacerse de un lotecito, lo sacrificaron para comprarme mi primer computadora. Jamás nunca podré pagarles ni agradecerles lo suficiente.

Aún recuerdo las palabras de recibimiento de la directora de la carrera, quien, además, impartía el curso de lógica: “Aquí no vienen a aprender a digitar, ni a usar paquetes ofimáticos, aquí van a aprender a programar una computadora”. Éxtasis…

Todos los cursos de programación los pasé con muy buenas notas, mas no todo fue fácil, muy a mi pesar también repetí un par de cursos. Pero no importaba, estar ahí y saber cómo funciona un programa, como decirle a una computadora que hacer en PASCAL o en FOX-DOS, era simplemente demasiado bueno para ser cierto. Era muy feliz.

Al final de la carrera universitaria las oscuras garras de la duda intentaron sujetar mi voluntad. ¿Y si no consigo trabajo? ¿Y si no es cómo lo imagino? ¿Y si no cumplo las expectativas? ¿Y si no gano lo suficiente? Y muchas otras preguntas asaltaban mi cabeza; algunas eran dudas razonables otras eran estúpidos miedos queriendo convertirse en excusas para tomar pésimas decisiones.

Al final, posterior a una práctica empresarial que me dejó un mal sabor, aunque fue experiencia al fin y al cabo, y luego de una única entrevista de trabajo, en Julio de 2001 llegué a mi segunda casa, a mi segundo hogar. ¡Y nada era como lo imaginaba! Todo es más difícil, mucho más complicado pero también excepcionalmente gratificante.

Desde entonces he programado casi siempre, algunas veces con más otras con menos responsabilidades, con muchos colegas al mismo tiempo o autogestionándome completamente solo y, aunque también se hacen muchas otras tareas de la forma más profesional posible como reuniones con clientes, levantamiento de requisitos, diseño, documentación, manuales, ayuda, aspectos gráficos, presentaciones de productos, capacitaciones, etc… para mí lo importante es que tarde o temprano termino programando y eso me hace simplemente feliz.

Aunque he tenido y sé que habrá días en que hubiera sido mejor no salir de la cama (porque para todos existen esos días complicados) y que habrá problemas grandes y pequeños que solucionar y situaciones difíciles que enfrentar, laborales y personales. El secreto para ser feliz la mayor parte de mi existencia ha consistido y consiste aún, en haber encontrado lo que realmente me apasiona (afortunadamente muy temprano) y haber tomado la decisión de dedicarme a eso como forma de vida. Hacer lo que me gusta, dedicarme a lo que realmente me gusta es mi secreto para ser feliz.

17 sept 2017

Scripts útiles: Ranking de Tablas y Búsqueda en Procedimientos Almacenados

 Algunas veces necesitamos algunos pequeños scritps de SQL para hacernos la vida más simple. A continuación dejo dos de éstos.

El primero lista las tablas en una base de datos en orden cantidad de registros en ellas en orden decendente.

SELECT  O.name TABLA, I.rows AS REGISTROS
FROM sysobjects O
	INNER JOIN sysindexes I ON I.id = O.id 
WHERE O.xtype= 'U'
	AND I.indid IN (0, 1)
ORDER BY REGISTROS DESC;

es útil para encontrar tablas candidatas a particionamiento .

El segundo sirve para buscar texto en los procedimientos almancenados o funciones

DECLARE @buscar nvarchar(max)='texto a buscar' 

SELECT OBJECT_NAME(id)
FROM sys.syscomments
WHERE [text] LIKE '%'+ @buscar +'%'
AND (
	OBJECTPROPERTY(id, 'IsProcedure') = 1
	OR OBJECTPROPERTY(id, 'IsInlineFunction') = 1
	OR OBJECTPROPERTY(id, 'IsScalarFunction') = 1
	OR  OBJECTPROPERTY(id, 'IsTableFunction') = 1
	)
GROUP BY OBJECT_NAME(id)

Muy útil cunado queremos buscar codigos de registros, parametros etc


10 dic 2015

Excepciones y más Excepciones (o el manejo de Errores)

Como sabemos las excepciones son el mecanismo por medio del cual el .Net Framework maneja los errores, éstas se “lanzan” cuando hay algo que produce un error, una excepción, un comportamiento indeseado y no manejado en nuestro código. Sabemos también que debemos darle tratamiento, no podemos ignorarlas, ya que harán que una aplicación deje de funcionar, se cuelgue, se cierre, o muestre horribles mensajes o páginas con las excepciones “crudas” al usuario final.

El esquema que solemos utilizar para manejar las excepciones son los bloques try{} catch{} finally{}, donde lo que deseamos ejecutar va dentro del bloque try, el tratamiento del error, si se produjese, va en el bloque cacth y lo que ejecutaremos siempre al final independientemente si se produjeron o no errores (liberar recursos por ejemplo) irá en el bloque finally

Exception Bubbling


Supongamos que tenemos varios (muchos) métodos o funciones que se llaman entre sí, de manera que el método 1 llama al método 2 que a su vez llama al método 3  y así consecutivamente hasta “n” métodos. ¿Qué sucede si en el método “n” se produce un error? Entra a jugar el mecanismo que se conoce como “exception bubbling” el cual consiste en que el error es “lanzando hacia arriba”, hacia el método que llamó al que produce el error, se añade información a la pila de seguimiento (StackTrace) y el error es nuevamente “lanzado hacia arriba” reproduciendo el mismo comportamiento hasta llegar al primer método de la cadena o hasta alguno en el que se dé un tratamiento apropiado. El siguiente código ilustra este comportamiento:

using System;

namespace BubblingExceptions
{
    internal static class Program
    {
        private static void Main(string[] args)
        {
            errorbubbling();
        }

        private static void errorbubbling()
        {
            try
            {
                Console.WriteLine("Inicia ejecución >> Llamando a Método 1");
                Metodo1();
                Console.WriteLine("Ejecución exitosa de Método 1");
            }
            catch (Exception ex)
            {
                Console.WriteLine("\nHa ocurrido una excepción:\n\n" + ex);
            }
            finally
            {
                Console.WriteLine("\nEjecutado bloque finally.");
                Console.ReadKey();
            }
        }

        private static void Metodo1()
        {
            Console.WriteLine("Método 1 >> Llamando al Método 2");
            Metodo2();
            Console.WriteLine("Ejecución exitosa de Método 2");
        }

        private static void Metodo2()
        {
            Console.WriteLine("Método 2 >> Llamando al Método 3");
            Metodo3();
            Console.WriteLine("Ejecución exitosa de Método 3");
        }

        private static void Metodo3()
        {
            Console.WriteLine("Método 3 >> Llamando al Método 4");
            Metodo4();
            Console.WriteLine("Ejecución exitosa de Método 4");
        }

        private static void Metodo4()
        {
            Console.WriteLine("Método 4 >> Llamando al Método 5");
            Metodo5();
            Console.WriteLine("Ejecución exitosa de Método 5");
        }

        private static void Metodo5()
        {
            Console.WriteLine("Método 5");
            throw new Exception("Exception de prueba de bubbling");
        }
    }
}

Como puede verse la excepción es lanzada desde el método más profundo, el número 5, hasta el que inicia la ejecución,  errorbubbling, mientras que en el camino recolecta información que es añadida a la pila de seguimiento. 

Por esto es que resulta imprescindible aprender a leer el StackTrace, el cual nos brindará información valiosa cuando estamos depurando nuestro código. Por ejemplo, en el resultado anterior, podemos saber que el error originalmente se produjo en la línea 62 del metodo5, y que este se llamó desde la línea 55 del método4, recorremos los llamados hasta encontrarnos que el error inicia en la línea 17 del método que comenzó la ejecución.

Aquí es importante reafirmar una regla de oro en el tratamiento de las excepciones: solo se captura una excepción (usando el catch)  cuando vamos a hacer algo productivo con ella, que en la mayoría de los casos debería ser tratarla adecuadamente impidiendo el bubbling (detener la propagación de la excepción) y, probable e idealmente, registrar el error en una bitácora (log).  Esto se ilustra de la siguiente manera:

private static void errorbubbling()
{
    try
    {
        Console.WriteLine("Inicia ejecución >> Llamando a Método 1");
        Metodo1();
        Console.WriteLine("Ejecución exitosa de Método 1");
    }
    catch (Exception ex)
    {
        Console.WriteLine("\nHa ocurrido una excepción:\n\n" + ex);
    }
    finally
    {
        Console.WriteLine("\nEjecutado bloque finally.");
        Console.ReadKey();
    }
}

private static void Metodo1()
{
    Console.WriteLine("Método 1 >> Llamando al Método 2");
    Metodo2();
    Console.WriteLine("Ejecución exitosa de Método 2");
}

private static void Metodo2()
{
    Console.WriteLine("Método 2 >> Llamando al Método 3");
    Metodo3();
    Console.WriteLine("Ejecución exitosa de Método 3");
}

private static void Metodo3()
{
    Console.WriteLine("Método 3 >> Llamando al Método 4");
    Metodo4();
    Console.WriteLine("Ejecución exitosa de Método 4");
}

private static void Metodo4()
{
    Console.WriteLine("Método 4 >> Llamando al Método 5");
    Metodo5();
    Console.WriteLine("Ejecución exitosa de Método 5");
}

private static void Metodo5()
{
    try
    {
        Console.WriteLine("Método 5");
        throw new Exception("Exception de prueba de bubbling");
    }
    catch (Exception ex)
    {
        Console.WriteLine("\nHa ocurrido una excepción en el Método 5:\n\n" + ex);
        // Manejo del error impiendo el bubbling, idealmente log del error
    }
    finally
    {
        Console.WriteLine("\nEjecutado bloque finally del método 5.");
    }
}

Como puede verse el StackTrace se reduce considerablemente pues el bubling de la excepción se detiene en el mismo método en el que se produce el error (siendo claro, en este caso, del todo, no habría bubbling), además se constata que los temas métodos completan su ejecución, finalmente el catch del método errorbubbling no se ejecuta, pero si todos los bloques finally.

El costo de los errores (malas prácticas)


¿Hay una penalización de rendimiento por el manejo de los errores? Por supuesto, que desde luego, que claro, que obviamente que sí…

El manejo de los errores tiene un costo significativo, por ejemplo una práctica que puede volverse común es utilizar el try…cacth de la siguiente manera:

            try
            {
               // Código a ejecutar
            }
            catch (Exception ex)
            {
                throw ex;
            }      
O bien esta otra variante:

            try
            {
               // Código a ejecutar
            }
            catch (Exception ex)
            {
                throw;
            }     
Lo que provocará es que el error sea relanzado, no por el .Net Framework, si no, explícitamente por el  código del desarrollador. Utilizando la primer práctica el código de nuestro ejemplo queda de la siguiente manera:

private static void errorbubbling()
{
    try
    {
        Console.WriteLine("Inicia ejecución >> Llamando a Método 1");
        Metodo1();
        Console.WriteLine("Ejecución exitosa de Método 1");
    }
    catch (Exception ex)
    {
        Console.WriteLine("\nHa ocurrido una excepción:\n\n" + ex);
    }
    finally
    {
        Console.WriteLine("\nEjecutado bloque finally.");
        Console.ReadKey();
    }
}

private static void Metodo1()
{
    try
    {
        Console.WriteLine("Método 1 >> Llamando al Método 2");
        Metodo2();
        Console.WriteLine("Ejecución exitosa de Método 2");
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

private static void Metodo2()
{
    try
    {
        Console.WriteLine("Método 2 >> Llamando al Método 3");
        Metodo3();
        Console.WriteLine("Ejecución exitosa de Método 3");
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

private static void Metodo3()
{
    try
    {
        Console.WriteLine("Método 3 >> Llamando al Método 4");
        Metodo4();
        Console.WriteLine("Ejecución exitosa de Método 4");
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

private static void Metodo4()
{
    try
    {
        Console.WriteLine("Método 4 >> Llamando al Método 5");
        Metodo5();
        Console.WriteLine("Ejecución exitosa de Método 5");
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

private static void Metodo5()
{
    try
    {
        Console.WriteLine("Método 5");
        throw new Exception("Exception de prueba de bubbling");
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Usando la segunda practica queda de la siguiente manera:

private static void errorbubbling()
{
    try
    {
        Console.WriteLine("Inicia ejecución >> Llamando a Método 1");
        Metodo1();
        Console.WriteLine("Ejecución exitosa de Método 1");
    }
    catch (Exception ex)
    {
        Console.WriteLine("\nHa ocurrido una excepción:\n\n" + ex);
    }
    finally
    {
        Console.WriteLine("\nEjecutado bloque finally.");
        Console.ReadKey();
    }
}

private static void Metodo1()
{
    try
    {
        Console.WriteLine("Método 1 >> Llamando al Método 2");
        Metodo2();
        Console.WriteLine("Ejecución exitosa de Método 2");
    }
    catch (Exception ex)
    {
        throw;
    }
}

private static void Metodo2()
{
    try
    {
        Console.WriteLine("Método 2 >> Llamando al Método 3");
        Metodo3();
        Console.WriteLine("Ejecución exitosa de Método 3");
    }
    catch (Exception ex)
    {
        throw;
    }
}

private static void Metodo3()
{
    try
    {
        Console.WriteLine("Método 3 >> Llamando al Método 4");
        Metodo4();
        Console.WriteLine("Ejecución exitosa de Método 4");
    }
    catch (Exception ex)
    {
        throw;
    }
}

private static void Metodo4()
{
    try
    {
        Console.WriteLine("Método 4 >> Llamando al Método 5");
        Metodo5();
        Console.WriteLine("Ejecución exitosa de Método 5");
    }
    catch (Exception ex)
    {
        throw;
    }
}

private static void Metodo5()
{
    try
    {
        Console.WriteLine("Método 5");
        throw new Exception("Exception de prueba de bubbling");
    }
    catch (Exception ex)
    {
        throw;
    }
}


Como puede verse, no es inocua la elección entre un método u otro. Si usamos throw ex; el StackTrace se reinicia con cada llamada, perdiéndose la información previa del error, cosa que no sucede si únicamente usamos throw; por lo que, generalmente, es preferible usar throw; en lugar de throw ex;.

Llegados a este punto nos preguntamos ¿y el costo? Pues bien realizamos algunas pruebas. En los siguientes pruebas se eliminaron todos los console.write dentro de los métodos para controlar solo el manejo de errores, los resultados son los siguientes:





 

Conclusiones

- El costo del manejo de las excepciones es bastante elevado.
- Es preferible manejar el error en el método en el que se produce el error y evitar el bubbling.
- Si el punto anterior no es viable, la regla es no usar catch a menos que se vaya a tratar el error apropiadamente, es mejor evitar el try catch si el error se va a manejar en el método que llama al actual, es decir, si solo se va usar throw dentro del catch, es mejor no hacerlo.
- Entre throw; y throw ex; es mejor elegir thow; ya que mantiene el StackTrace.
- No olvidar registrar la excepción en una bitácora o en el visor de eventos para examinar apropiadamente el problema que lo produce.
- Siempre es preferible no lanzar un error.

Gracias a nuestro"kohāi" Brayan por señalarnos que estábamos reproduciendo un código ineficiente en alguno de los manejos de excepciones. Siempre es importante hacer retrospectivas y atender a las sugerencias para mejorar.

29 nov 2015

Listas y Linq

Linq definitivamente es una herramienta que necesitamos dominar, son muchos los escenarios en los que podemos aprovechar su potencia para simplificar las tareas que otrora nos tomaría varias líneas de código. Aquí unas pequeñas pinceladas con arreglos y listas.

Supongamos que tenemos dos arreglos de enteros y necesitamos saber si ambos se intersecan y cuáles son los números que comparten. Con Linq sería algo así:

static void Main(string[] args)
{
    int[] x = { 1, 2, 3, 4, 5 };
    int[] y = { 2, 4, 6 };
    int[] z = x.Intersect(y).ToArray();
    System.Diagnostics.Debug.WriteLine("Resultado: " + 
    string.Join(",", z.Select(s => s.ToString())));
}
¡Simple!
Otro ejemplo
Supongamos que tenemos la siguiente clase

public class Empleado
{
    public int idEmpleado { get; set; }
    public string nomEmpleado { get; set; }
    public decimal mtoSalario { get; set; }
}
Tenemos un array de enteros y queremos inicializar una lista de empleados únicamente con los id a partir del array, procedemos así:

static void Main(string[] args)
{
    int [] ids =  { 1, 2, 3, 4, 5 };
    List empleados = ids
        .Select(i => new Empleado() { idEmpleado = i })
        .ToList();
    System.Diagnostics.Debug.WriteLine("Cantidad: " + empleados.Count);
}
Una más. Supongamos que adicionalmente a la clase anterior de tenemos otra correspondiente a clientes

public class Cliente
{
    public int idCliente { get; set; }
    public string nomCliente { get; set; }
}
Supongamos que comparten un mismo origen, de manera que un cliente y empleado con la misma id, son la misma persona, teniendo dos listas: una de empleados y otra de clientes, queremos saber cuáles empleados también son clientes, entonces:

static void Main(string[] args)
{
    //Clientes
    List clientes = new List (){
        new Cliente() {idCliente=1, nomCliente= "María"}, 
        new Cliente () {idCliente=2, nomCliente="Jose"},
        new Cliente() {idCliente=3, nomCliente="David"}, 
        new Cliente() {idCliente=4,nomCliente="Ana"} 
    };

    //Empleados
    List empleados = new List(){
        new Empleado() {idEmpleado=2, nomEmpleado="Jose", mtoSalario=3500},
        new Empleado() {idEmpleado=4, nomEmpleado="Ana", mtoSalario=5500},
        new Empleado() {idEmpleado=6, nomEmpleado="Carlos", mtoSalario=3500}
    };

    //ids de clientes
    List idsClientes = clientes.Select(s => s.idCliente).ToList();

    //Empleados que son Clientes
    List empleadosClientes = empleados
        .Where(e => idsClientes.Contains(e.idEmpleado))
        .ToList();

    System.Diagnostics.Debug.WriteLine("Empleados y Clientes: " + 
        string.Join(", ", empleadosClientes.Select(c => c.nomEmpleado.ToString())));
}
Como podemos ver son muchas las posibilidades que nos ofrece Linq, o sus Extension Methods para ayudarnos en nuestra labor.

24 oct 2015

RPAD y LPAD en TSQL

Son un par de funciones que los que algún día estuvimos trabajando con Oracle estrañamos en SQL Server, Básicamente permiten rellenar a la izquierda o derecha con un caracter dado. Aquí una implementación de ambas en T-SQL

--Permite rellenar con un caracter dado a la izquierda hasta completar
-- la longitud deseada
CREATE FUNCTION [dbo].[fnPADL](
 @strOrigen VARCHAR(50), --String original
 @intlen INT,            --longitud a completar
 @chrCaracter CHAR)      --Caracter con el que se rellena
 RETURNS VARCHAR(50)
 AS 
 BEGIN
    DECLARE @len INT = LEN(@strOrigen)
    RETURN (
        CASE 
            WHEN @len < @intlen THEN REPLICATE(@chrCaracter, @intlen - @len) + @strOrigen 
            ELSE  @strOrigen
        END)
END

--Permite rellenar con un caracter dado a la derecha hasta completar
-- la longitud deseada
CREATE FUNCTION [dbo].[fnPADR](
 @strOrigen VARCHAR(50), --String original
 @intlen INT,            --longitud a completar
 @chrCaracter CHAR)      --Caracter con el que se rellena
 RETURNS VARCHAR(50)
 AS 
 BEGIN
    DECLARE @len INT = LEN(@strOrigen)
    RETURN (
        CASE 
            WHEN @len < @intlen THEN  @strOrigen + REPLICATE(@chrCaracter, @intlen - @len)
            ELSE  @strOrigen
        END)
END
Ambas funciones se aseguran que si la longitud de la palabra es mayor o igual a la longitud a cubrir devuelva la misma palabra.

Su forma de utilización sería

SELECT DBO.fnPADL ('HOLA',6,'X')
--devuelve: XXHOLA

SELECT DBO.fnPADR ('HOLA',6,'X')
-- devuelve: HOLAXX

SELECT DBO.fnPADL ('HOLA',2,'X')
-- devuelve: HOLA
Es muy muy importante a tener en cuenta que aunque estén disponibles las UDF (User-Defined Function) que devuelven escalares (como las que acabamos de definir) no es muy recomendable su uso, principalmente con grandes conjuntos de datos, En otro post intentaré ahondar mas en el por qué, quizás con algunas comparativas pero de momento el consejo sería: siempre que sea posible usar la lógica "in line" o dentro de la misma sentencia SQL, por ejemplo es más eficiente esto

SELECT REPLICATE('X',6 - LEN(miColumna)) + miColumna
FROM miTabla
en lugar de esto:

SELECT  DBO.fnPADL (miColumna,6,'X')
FROM miTabla
Obviamente con una cantidad de datos significativa, Además para usar la primera sentencia tenemos que estar seguros que la longitud de miColumna no es mayor a 6.

En todo caso recordar que si vamos a usar UDF escalares debemos realizar pruebas con buenos volúmenes de datos.