Ir al contenido principal

Sobre arquitectura en capas – Parte 1

Aun veo proyectos que separan los componentes de la aplicación en capas, utilizando el viejo modelo de 3 capas, el cual siento que ya no es la mejor opción ya que la forma de desarrollar software ha cambiado. En esta serie de artículos pretendo explicar porque ya no es necesaria una separación en 3 capas al momento de desarrollar un nuevo proyecto de software.

Primero debo empezar por definir qué es es la arquitectura en capas para mi, así que esta primera parte trata sobre eso.

¿Qué es la arquitectura en capas?

La arquitectura en capas consiste en separar las responsabilidades de nuestra aplicación de una manera horizontal. Esto se hace con la intención de elevar el nivel de abstracción. Ocultar la plomería de la aplicación poniendo una capa de abstracciones sobre ella. Las típicas capas de esta arquitectura, iniciando de abajo hacia arriba, se describen a continuación.

Capa de acceso a datos (también conocida como DAL por sus siglas en ingles): Es donde se escribe el código que habla con la base de datos. Es en esta capa donde se definen las consultas a la base de datos (el SQL). No realiza validaciones entre entidades, sólo las validaciones que van hacia la base de datos. La intención de esta capa es que el resto de la aplicación no se preocupe de los detalles (en cierta medida) de la estructura de la base de datos y trabaje a un nivel de objetos. Es la encargada de la entrada y salida de datos hacia y desde la base de datos. Ya que no debe de preocuparse de las reglas de negocio el código de la capa debería de ser fácil de seguir y de mantener. Las capas construidas encima de esta (es decir que usen esta capa) deben de dejar de pensar en tablas y registros para pensar en objetos y colecciones.

Capa de reglas de negocio (BL): Una vez que tenemos la abstracción de la capa de acceso a datos, sobre ella se construye una capa. En esta capa es donde se escriben las reglas de negocio, validaciones que involucran varias entidades, validación de estados y condiciones definidas en los requerimientos. Usa a la capa de acceso a datos para realizar las consultas y actualizaciones a la base de datos. La capa de negocio no sabe cómo es presentada la información al usuario o de cómo fue capturada por él. Al no preocuparse de como se presenta la información (UI) o de como es que se almacena (DAL), en el código solo deben observarse que las reglas (de negocio) definidas en los requerimientos se cumplan.

Capa de presentación (UI): Lo que el usuario ve. Es la capa donde se crean los componentes de la interfaz de usuario. Esta capa utiliza a la capa de negocio para realizar la tarea que el usuario requiera. La capa de negocio validará y regresará el resultado o error y la capa de presentación los mostrará al usuario. Entonces el código en esta capa sólo se encarga de pasar valores a la capa de negocio y de desplegar información, en la interfaz de usuario, que viene de la capa de negocio.

Hagamos un ejemplo para entender mejor a que se refiere cada capa. Supongamos que se nos pide que en la aplicación que estamos desarrollando un usuario pueda ingresar al sistema con un nombre de usuario (username) y contraseña validos. Separando nuestra aplicación en capas como las definidas anteriormente tendríamos las siguientes clases (en C#).

Primero la capa de acceso a datos

namespace Dal
{
  public class UserRepository
  {
    public User FindByUsername(string username)
    {
      User user = null;
      var sql = "SELECT * FROM User WHERE Username = @Username";
      using(var connection = new SqlConnection(Config.ConnectionString)){
        var cmd = new SqlCommand(sql, connection);
        cmd.Parameters.AddWithValue("@Username", username);
        connection.Open();
        using(var reader = cmd.ExecuteReader())
        {          
              user = reader.read() ? 
                 new User(username, reader["password"]) : null;
        }
        return user;
      }
    }
  }
}

Ahora la capa de reglas de negocio:

namespace BL
{
  public class UsersService
  {
    public bool ValidateUser(string username, string password)
    {
      var userRepository =  new UserRepository();
      var user = userRepository.FindByUsername(username);
      if (user == null) return false;
      var cryptoService = new CryptoService();
      return cryptoService.ComputeHash(password) == username.Password;
    }
  }
}

Por último la capa de presentación:

...
void LoginButton_Click(object sender, EventArgs e)
{
   var usersService = new UsersService();
   if (usersService.ValidateUser(usernameTextbox.Text, passwordTextbox.Text))   
       MessageBox.Show("Bienvenido");
   else
       MessageBox.Show("Usuario o contraseña incorrectos");
}
...

Aquí puede verse la separación de la lógica en capas. En lugar de hacer la consulta a la base de datos directamente en el método de clic del botón, la capa de presentación delega la validación del usuario a la capa de negocio. La capa de negocio a su vez delega a la capa de acceso a datos la creación y ejecución de las consultas en SQL sobre la base de datos.


Así era como desarrollábamos una aplicación hace años; pero ya no.


Artículo relacionado: Sobre arquitectura en capas – parte 2

Comentarios

  1. Me pica la curiosidad de saber que alternativa tenemos...

    ResponderBorrar
  2. Últimamente he visto muchos artículos y comentarios de viejas prácticas que se consideran hoy obsoletas. Lamentablemente en mi muy humilde opinión creo que hace falta más información de porque nacieron, o sea que problemática del desarrollo del software se quiere prevenir y como lo logra. Además también es obvio que hay casos en los que de verdad no aplican, pero no se podrá saber cuándo si usarlos y cuando no si no se conoce para que nos sirven. En proyectos pequeños en donde no hay más de dos desarrolladores en un proyecto de no más de tres meses estoy de acuerdo contigo, no es necesario programar más de tres capas, de lo contrario creo que es una excelente patrón de diseño.
    http://msdn.microsoft.com/en-us/library/ff650706.aspx

    ResponderBorrar
  3. Por hacer una analogía, sabemos que los candados tienen el propósito de solo dejar pasar a quienes tienen la llave, pero cuando no se usa el candado correcto esto es lo que pasa: http://devopsreactions.tumblr.com/post/56770243712/this-looks-secur-wait-a-minute

    Así croe que está ocurriendo en la industria, muchos no están utilizando el patrón de diseño correctamente y lo que los programadores a la larga creen con justa razón es que el patrón de diseño no es útil ya que les da muchos problemas el implementarlo y ningún beneficio.

    ResponderBorrar
  4. Yo tambien tengo mucha curiosidad de conocer las alternativas.

    Pero desde mi punto de vista, no todos los proyectos son iguales y para diseñar una arquitectura se tienen que tomar en cuenta muchas cosas, no solamente lo que 'esta de moda' o el supuesto estandar de la industria.

    Si bien la arquitectura en 3 capas es de las mas adoptadas, creo que muchas veces es implementada por las razones equivocadas. El simple hecho de usar capas en un proyecto por que 'asi me enseñaron' o por que 'es el estandar' no son razones suficientes y muchas veces se pierde el tiempo programando para prevenir cosas que jamas van a ocurrir.

    Si la razon por la que usas un diseño en capas es para 'poder reemplazar cualquier capa sin afectar las demas capas' entonces puede que estes perdiendo tu tiempo.

    Ojo, tienes que analizar si la posibilidad de un reemplazo de cualquiera de las capaz es tan siquiera factible.

    La arquitectura muchas veces la analizamos desde el ambito tecnico, pero nos olvidamos del ambito administrativo, algo que no se puede dejar de lado al momento de gestionar cualquier proyecto. Creo que la arquitectura en capas facilita ciertas funciones administrativas, al poder 'descomponer' tu proyecto en areas definidas y separar de mejor manera las tareas. Me ha tocado trabajar en varios proyectos donde un equipo de alrededor de 5 personas trabaja sobre el mismo codigo y la arquitectura en capas ha ayudado a delegar las tareas. Puedes tener 2 personas trabajando en el front-end y otras 2 en el DAL sin que nadie se pise los talones.


    En conclusion mi postura es, todo es cuestion de hacer las cosas con un proposito claro en mente y no como borreguitos. Debemos de aprender a aplicar muy bien el Separation of Concerns (SoC)pero nunca olvidarnos del KISS :) (Keep it simple, stupid!)




    ResponderBorrar

Publicar un comentario

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