Aportando un poco de coherencia en los controladores

8. July 2011 14:39 by Oscar.SS in Desarrollo .NET, Desarrollo Web  //  Tags: ,   //   Comments (2)

Cuando formamos parte de un proyecto en el que participan varios desarrolladores, puede suceder si no se tiene una fuerte política de nombrado (desde luego algo poco usual) en las acciones y los métodos, que cada desarrollador elija el nombre que mejor le parezca en ese momento.

De esta forma en un mismo proyecto o solución, podemos encontrarnos para especificar acciones que conceptual y funcionalmente representan lo mismo sobre diferentes entidades, nombres como GetCustomerById,  LoadProductById, DeleteProduct, UserDelete. De esta forma tendríamos URLs de navegación de esta forma:

/Customer/GetCustomerById

/Product/LoadProductById

/Product/DeleteProduct  o   /User/UserDelete

 

En mi opinión creo que este modo de proceder tiene algunas desventajas.

  • Como desventaja para nosotros, los que tenemos que picar código o leer el de otros compañeros, está el hecho de que sería más cómodo si todas las acciones de eliminar una entidad se nombraran simplemente Delete por ejemplo. No importa si es un producto, un cliente, o lo que sea. 

Por ejemplo, cuando estemos escribiendo URLs a mano en el explorador, algo habitual durante un desarrollo en el que no se han implementado todas la funcionalidades de navegación de la aplicación, nos será muy fácil acordarnos que todos los listados o informes se devuelven con Report. Así tendríamos:

/Products/Report

/Orders/Report

/Customer/Report


En lugar de que cada desarrollador elija el que mejor le cuadre en ese momento...

/Product/GetReport

/Orders/GetAllReport

/Customer/GetReportCustomer

  •  Desde un punto de vista puro de la programación orientada a objetos, no hay que olvidar que los controladores no son más que clases, y por lo tanto, parece lógico pensar que si tienes distintas clases con los mismos métodos habría que implementar una interfaz. Y quién sabe, a lo mejor también una clase abstracta para escribir el código de estos métodos en un solo sitio.
  • Como desventaja para los usuarios, si se le puede llamar así, es que ellos tengan a la vista (si alguno se fija) una mayor coherencia de las URLs por las que navega. Creo yo que da un sentido más ordenado a nuestro site.
  • No sé si también puede tener algún efecto negativo en cuanto a SEO. Habría que estudiarlo pero será en otra ocasión. De todas formas si alguien tiene algo que aportar a este aspecto que lo comente por favor.
 
Una posible solución podría ser utilizar inferfaces genéricas. Supongamos que vamos a establecer el CRUD básico sobre todas las entidades de nuestra aplicación. Entonces podríamos definir una interfaz como la siguiente:
 
    internal interface IControllerBase<in TEntity, in TEntityId>
        where TEntity : 
class 
        
where TEntityId: struct
    
{
        ActionResult Index()
;
        
ActionResult Create();
        
ActionResult Create(TEntity entity);
        
ActionResult Edit(TEntityId id);
        
ActionResult Edit(TEntity entity);
        
ActionResult Details(TEntityId id);
        
ActionResult Delete(TEntityId id);
    
}
 
Como podemos apreciar la interfaz permite trabajar con dos entidades genéricas. Una clase cualquiera que podrá ser una entidad de negocio o un ViewModel, lo que necesitemos mientras sea un tipo por referencia (class). Y también admite una entidad de tipo estructura (struct) que en nuestro caso representará el id de la entidad de negocio.
 
Ahora implementemos esta inferfaz en un controlador.
 
    public class ProductsController : Controller, IControllerBase<Product, int>
    {
        [HttpGet]
        
public ActionResult Index()
        {
            
return View(ProductsServices.GetAll());
        
}

        [HttpGet]
        
public ActionResult Create()
        {
            
return View();
        
}

        [HttpPost]
        
public ActionResult Create(Product entity)
        {
            
if (!ProductsServices.NewProduct(entity))
                
return View("Error");

            return 
RedirectToAction("Details"new { id entity.ProductID });
        
}

        [HttpGet]
        
public ActionResult Edit(int id)
        {
            
return View(ProductsServices.GetById(id));
        
}

        [HttpPost]
        
public ActionResult Edit(Product entity)
        {
            
if (!ProductsServices.UpdateProduct(entity))
                
return View("Error");

            return 
RedirectToAction("Details"new { id entity.ProductID });
        
}

        [HttpGet]
        
public ActionResult Details(int id)
        {
            var product 
ProductsServices.GetById(id);
            return 
View(product);
        
}

        [HttpGet]
        
public ActionResult Delete(int id)
        {
            
if (!ProductsServices.RemoveProduct(id))
                
return View("Error");

            return 
RedirectToAction("Index");
        
}
    }
 
 
En otros controladores, que naturalmente contengan las mismas acciones base, implementaríamos la interfaz y escribiríamos el código con la lógica de navegación específica para cada acción.
 
Si ahora necesitáramos añadir una acción o método que solo se va a utilizar en algunos controladores, podríamos definir otra interfaz con este método solamente e implementar la interfaz solo en los controladores que lo usen.
 
Supongo que alguno se estará preguntando si merece la pena el esfuerzo. Yo también me lo pregunto pero sinceramente creo que aporta más ventajas que desventajas. No cuesta tanto ser ordenados y dar un poco de coherencia a nuestro código aunque sea en algo tan simple como esto.
 
¡Se admiten opiniones!  :-)

Comments (2) -

JAGH
JAGH
7/12/2011 7:08:51 PM #

Nada mas cierto, aveces hasta uno mismo termina poniendo nombres similares (editar, modificar; borrar, eliminar) en las acciones que permite el controlador, con el uso de interfaz se eliminan muchas inconsistencias que podrian causarse al momento de entender el codigo que hemos producido o estamos leyendo de alguien mas.

Óscar.SS
Óscar.SS
7/12/2011 7:30:58 PM #

Hola Jagh:

Si, aunque sea un tema un poco trivial, no creo que cueste tanto tenerlo en cuenta. De todas formas no deja de ser una cuestión de elección personal o de equipo

Un saludo y gracias por comentar.

Recent Comments

Comment RSS

Month List