Ir al contenido principal

La tentación de la capitis

Cada que inicio un nuevo proyecto lo veo como una oportunidad para organizar diferente la estructura, la arquitectura, a fin de mejorar la forma en que se desarrolla el proyecto.

En esta etapa es fácil caer en la tentación de crear varias capas (capitis), con esto me refiero a la intención de separar toda la lógica o "responsabilidades" en proyectos separados. Intentar que el modelo del dominio del problema quede "puro", es decir, limpio de dependencias externas. Sin "manchas" con detalles de frameworks. Que alguien al abrir el proyecto vea nombres de carpetas que tengan que ver con el negocio, y no con detalles "sucios" como controllers, views, etc.

Es divertido definir la capa de negocio (o dominio) y estar programando abstracción, tras abstracción. Para después crear proyectos de implementaciones concretas usando cierta tecnología, librería o framework. Como no queremos tener implementaciones concretas, entonces definimos interfaces. Las cuales serán consumidas por la capa de presentación, claro que sin conocer las implementaciones concretas. Así será "fácil" cambiar (pensamos) de  implementación sin afectar la aplicación en un futuro.

Por poner un ejemplo (cuando se trabaja con .NET) se puede llegar a tener un proyecto "Negocio" que solo tiene clases que contienen el "core" del problema e interfaces para todo lo demás que necesita contener dependencias de terceros. Después se agrega un proyecto para cada tecnología que necesitas para realmente hacer las cosas, como "Negocio.EntityFramework" que es una implementación de nuestro proyecto usando EntityFramework para guardar los datos. Y nos sentimos bien porque en un futuro "podríamos" tener un proyecto "Negocio.FileSystem" que guarda los datos en disco directamente o una implementación que los guarde en MongoDB "Negocio.MongoDb". Esto por poner ejemplos. También podemos abstraer el Web como una presentación más y llegar a tener más interfaces e implementaciones concretas que podemos cambiar. Hay veces que se agrega una capa de "servicios" que lo único que haces es llamar a la capa de acceso a datos, incluso a veces es peor y llama a una capa de repositorios que entonces esa sí llama a la base da datos.

Lo que termina pasando, la mayoría de las veces que he visto esa arquitectura, es que solo se tiene una implementación para cada Interfaz. Es decir tantas abstracciones para nada. Solo es más código para ocultar la implementación concreta, al final esa abstracción contendrá fugas para así poder acceder a la funcionalidad que tiene la implementación concreta. A veces se usa el pretexto de que las pruebas serán más fáciles; pero la verdad es que en muchos de esos proyectos ni si quiera hay pruebas unitarias.

Darle mantenimiento a un proyecto así es más complejo de lo necesario, por varias razones:
  1. Es más difícil encontrar la implementación concreta de un método porque la mayoría del código tiene llamadas a interfaces, debes buscar en otro proyecto la implementación.
  2. La configuración necesaria es mayor, se necesita configurar todos los tipos en un contenedor de dependencias o usar el patrón de service locator (que tiene sus propias desventajas) para instanciar las clases concretas que implementan las interfaces del core.
  3. La cantidad de código escrito es mayor (sin ningún beneficio, si solo tienes una implementación), por lo tanto entenderlo es más complicado.
  4. Como la cantidad de código es mayor, hay mayor posibilidad de bugs. 
  5. Un cambio trivial puede significar realizar cambios a todas las capas, debido a las abstracciones con fugas.
Aún conociendo esas desventajas y haber tenido que mantener proyectos de este tipo, donde incluso he visto que se agregaran abstracciones para obtener la fecha y hora del sistema. Aun así cuándo estoy por iniciar un proyecto nuevo, tengo esa sensación de dejar "puro" el dominio y las implementaciones concretas declararlas en otro proyecto. Aún sabiendo que no vale la pena, como que se antoja dejarme llevar en ese viaje creando abstracción sobre abstracción.

A veces siento que he logrado separarlo en capas, con moderación, limitando mis abstracciones. Es decir sin llegar al extremo de tener puras interfaces en el dominio. Pero casi siempre tengo que recordar que "No voy a necesitar otra implementación", pensar en YAGNI y el principio KISS. Recordar que siempre puedo refactorizar si se llega a ocupar. el refactoring es fácil porque el código es poco.  

Siempre es más fácil agregar una capa después, que darte cuenta que no la ocupabas y tratar de quitarla. Limitemos nuestras abstracciones.

Comentarios

Entradas más populares de este blog

Bloqueos

Una de las preguntas típicas de las juntas matutinas en los equipos de desarrollo de software es ¿Hay algún bloqueo? Si lo hay, se trata de ver qué es lo que está esperando esa persona y encontrar la forma de que se desbloquee; pero ¿Qué son los bloqueos? Los bloqueos son obstáculos que te impiden realizar o avanzar en tu trabajo. Evitan que puedas seguir progresando en el proyecto.

He notado que es común en las personas con menos experiencia decir que tienen un bloqueo cuando están batallando, debido a su poca experiencia, en la forma de resolver un problema. Han intentado varias formas y se empiezan a quedar sin ideas de como puede ser resuelto el problema o como pueden cumplir con el requerimiento especificado. Al quedarse sin opciones de qué intentar dicen que tienen un bloqueo con la tarea y que a menos que alguien les diga como resolverlo, no se puede avanzar en la tarea.

En personas con más experiencia, ese tipo de bloqueos no ocurren, una persona con experiencia ha visto pro…

Firebird 2.1 UPDATE OR INSERT

Another great feature that I like in Firebird 2.1 is the UPDATE OR INSERT statement. It's a really time saver and it makes the SQL cleaner.

For example suppose I have a products table like the one I use in my last post and an inventory table to store the product stock. Before Firebird 2.1 if I want to set the stock for a product I needed to check if a record for that product_id already exists; if the product_id already exists then I write an update. If not then I write an insert statement. So I ended up with something like this:


IF EXISTS(SELECT * FROM inventory WHERE product_id = :product_id ) THEN
UPDATE
inventory
SET
stock = :stock
WHERE
product_id = :product_id;
ELSE
INSERT INTO inventory
(product_id, stock)
VALUES
(:product_id, :stock);

In this example I only update one field but when I have to update a big table I ended up with a big chunk of code and thinking: "there should be another (better) way to do this".

Fortunately now with Firebird 2.1 there…

Database Mail en MS SQL Server 2005

Configuración de Database Mail en MS SQL Server 2005

Primero se debe de habilitar, ya que por omisión el componente esta deshabilitado, Utilizando el SSMS (SQL Server Management Studio)


Si no esta habilitado aparecerá un mensaje preguntado si lo habilita, después aparece esta ventana donde se pregunta al usuario que es lo desea hacer.


Seleccionamos la primera opción para crear un perfil.


Configuramos el perfil y le agregamos por lo menos una cuenta.


Seleccionamos el perfil como public y default.


Para mandar correo se utiliza el procedimiento msdb.sp_send_dbmail por lo tanto el usuario que intente mandar correo debe de tener permiso para la base de datos msdb.

Referencias:
http://www.sqlservercentral.com/columnists/cBunch/introtodatabasemailinsql2005.asp