18 nov 2017

Arquitectura RESTFul


Estas son las notas del primer capitulo del libro Hands-On RESTful API Design Patterns and Best Practices que recomiendo encarecidamente adquirir, ya que aclara los conceptos que aquí apenas se mencionan. Lo siguiente es un resumen que está lejos de tener el valor de todos los matices que abarca el libro.

Algunos conceptos o definiciones previos:

XML/JSON (Extensible Markup Language/ JavaScript Object Notation) es el formato que provee metadata para los datos que son contenidos dentro de los mensajes que intercambian los sistemas/servicios

SOAP (Simple Object Accces Protocol): usado para para transferir datos.

WSDL (Web Services Description Language) : se usa para definir los servicios disponibles que pueden ser consumidos

UDDI (Universal Description, Discovery, and Integration) es una lista de los servicios disponibles.

URI (Uniform Resource Identifier) se usa para identificar la ubicación de recursos en una red.

API (Application Programming Interface) especifica como un componente de software se comunica con otros componentes.

REST (Representational State Transfer) es una manera o estilo de exponer funciones y datos para ser consumidos en un ambiente distribuido.

SOA (Service Oriented Architecture): define estándares y enfoques para el diseño de web services y cómo estos se comunican entre sí. Aquí, un web service es la representación lógica actividades de negocio repetibles,  son una operación que tienen un resultado específico: obtener el costo de un producto, actualizar el inventario, obtener la ubicación de un negocio. Para el consumidor el webservice que consume es una caja negra. Estas alojados en servidores e interactúan con otras aplicaciones a través de interfaces.

ROA (Resourse Oriented Architecture): es una arquitectura fundada en la semántica de la web. Define un diseño estructural y guías para soportar e implementar interacciones con cualquier recurso conectado. En este contexto, cualquier entidad de negocio puede ser representado por como un recurso y pude ser accesible a través de una URI. Así en un sistema de recursos humanos cada empleado es una entidad (servicio) y sus detalles, salario, perfil, son asociaciones (descriptores) de una entidad y cada entidad puede permitir varias acciones (contratos).

Como se apuntó ROA está fundamentada en la semántica de la web ¿Cuál semántica? Las operaciones o “verbos” que implementa el protocolo HTTP , es decir:

VERBO USO
GET Leer las representaciones de un recurso
PUT Creación de un nuevo recurso.
DELETE Eliminación del recurso (y de los recursos ligados, de forma opcional)
POST Modificación del recurso.
HEAD Meta información del recurso.

Ahora, para decir con propiedad que tenemos una API que es REST ésta debe cumplir con ciertas restricciones  y propiedades (dadas por Roy Fielding, quien propuso en primera instancia el concepto de REST) Entre las propiedades están: se exponen recursos, no se mantiene estado entre requests, direccionabilidad (el recurso debe usar una dirección), uniformidad y usar el protocolo HTTP para la comunicación de los datos.

Entre las restricciones (Constraints) REST están:
  • Cliente-Servidor: La comunicación se da entre el cliente (o muchos clientes) que es quien quién solicita un servicio, utilizándolos mediante el envio de requests, y el servidor que es quien provee el servicio a consumir, manejando los request o solicitudes para acceder a los mismos. Clientes y servidor típicamente existen en un ambiente distribuido comunicándose a través de una red por medio de patrón request-respond.
  • Statelessness (sin estado): Significa que el servidor no mantiene ninguna información o estado contextual entre los requests. Dicho de otra forma cada llamado (request) del cliente debe contener toda la información necesaria de manera explícita para que el servidor pueda entenderlo y manejarlo de manera totalmente independiente. Esto asegura escalabilidad y confiabilidad del lado del servidor. Es importante señalar que es el cliente, entonces, quien debe mantener algún mecanismo para mantener contexto entre las llamadas al servidor.
  • Caching (Caché): en el contexto de REST se refiere a la posibilidad almacenar datos de uso frecuente de manera que parcial o totalmente se elimine la necesidad de la comunicación entre el cliente y el servidor, disminuyendo la latencia y mejorando el rendimiento en el lado del cliente. Hay diversas estrategias para el caching: browser caché, proxy caché, gateway cache (reverse proxy). Usualmente se usan algunos tags a nivel de headers para controlar el cache: expires, Cache-control,E-Tag, Last-Modified. (más información).
  • Interfaz Uniforme: como se mencionó anteriormente se refiere a la combinación de la semántica del HTTP, con el concepto de recurso, creando una interfaz uniforme. Es decir donde GET, es siempre leer, y DELETE es siempre eliminar con respecto a un recurso cualquiera este sea. Esto es parte del corazón de REST, Roy Fielding, instituyó cuatro principios necesarios para alcanzar a cabalidad la restricción de interfaz uniforme:
  1. Identificación de los recursos: cada recurso debe estar identificado inequívocamente  por medio de un URI. Así el URI para ubicar un empleado será https://api.MyRRHH.com/1.1/Planilla/Empleados/:id.json los datos devueltos podrán refinarse y mejorase con la evolución de las versiones pero está siempre será la forma de acceder al recurso empleado.
  2. Manipulación del recurso: se refiere a la independencia del URI de un recurso y los formatos en la que la información es devuelta al cliente. Puede que la misma URI exponga el recurso solicitado en diferentes formatos: JSON, XML, HTML,  PNG, SVG, etc (Multipurpose Internet Mail Extension (MIME))  permitiendo que el cliente manipule esta data según sus posibilidades y conveniencia. Para lograr esto el servidor habilita a través del tag Accept del Http header que el cliente le solicite el formato en que requiere el recurso. Separar la representación (formato) del recurso  de la URI del mismo es un aspecto crucial de REST.
  3. Mensajes Auto-Descriptivos: REST descansa sobre el principio de que tanto el request del cliente como el response del servidor son estandarizados (tienen cuerpo y metadata) y son autodescriptitvos es decir usan los tipos de mensajes: GET, HEAD, OPTIONS, PUT, POST y DELETE) de manera que son completamente comprendidos tanto por el servidor como por el cliente. De esta manera se tiene el mecanismo por medio del cual los mensajes contienen la información necesaria, manteniéndose cada uno independiente, sin necesidad de mantener estados en el servidor.
  4. Hypermedia como el motor de Estado de Aplicación (Hypermedia as the Engine of Application State (HATEOAS)): Sin esta característica no podemos argumentar que un servicio es RESTful, fue introducida en el modelo Richardson Maturity Model (RMM) por Leonard Richardson. Se trata del siguiente paso una vez tenemos un servicio que expone un recurso a través de un URI accesible a por medio de los verbos de HTTP, y consiste en brindar al cliente que consume un recurso la guía de qué es lo siguiente que puede hacer con él. Esto se realiza por medio de un dato más denominado de forma estándar “link” o “links” que acompaña la respuesta del servidor. Para ponerlo menos abstracto imaginemos un servicio que nos devuelve una lista de las citas disponibles de un doctor, con HATEOAS a cada uno de los  ítems devueltos se le añade un dato link que nos indica cual es el URI para tomar esa particular cita de manera que el cliente es guiado al siguiente paso o estado de la aplicación. Resumiendo, HATEOAS se refiere a que la representación de un recurso devuelta por un servicio incluye links que le indican a quien lo consume recursos relacionados con el mismo.
  • Sistemas en capas: consiste en sistemas que se componen de unidades que se comunican a través de interfaces predefinidas desempeñando diversas funciones. Estas capas puede estar físicamente separadas de manera que, por ejemplo, la API REST se instala en el servidor A, la autenticación se realiza en el servidor B y los datos se almacenan el servidor C. REST sugiere que los servicios pueden estar constituidos por múltiples capas, que éstas publican contratos de servicios y que, en un ordenamiento jerárquico, la lógica de una capa dada únicamente puede ser conocida por la capa inmediatamente superior o  inmediatamente inferior.
Resumiendo:
El mismo Roy Fielding, fundador del estilo REST, dejó claro que para que un API (servicio) se atribuya el estatus de RESTful debe cumplir con las restricciones de su estilo de arquitectura, es decir cumplir con:
  • Cliente-Servidor
  • Statelessness
  • Caching
  • Interfaz Uniforme
  • Sistema en capas.
Las metas de una arquitectura REST son cumplir con las siguientes propiedades:
  • Rendimiento
  • Escalabilidad
  • Simplicidad
  • Modificabilidad
  • Visibilidad
  • Portabilidad
  • Confiabilidad
  • Testeability (susceptible de probarse)
Una  vez mas sugerir la adquisición del libro Hands-On RESTful API Design Patterns and Best Practice para aclarar los conceptos que quedan oscuros en este resumen.

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.