2010-02-10 10 views
8

Estoy usando StructureMap por el momento, generalmente con autoconfiguración basada en convenciones (Scan()), y estoy buscando agregar caché basado en decorador a la tubería.Influencia de AOP con atributos a través de IoC; código de olor o elegante?

Si puedo configurar manualmente que está muy bien, pero Scan() es tan conveniente cuando se obtiene gran cantidad de dependencias ... Estoy jugando con señalar caché sugerencias en la interfaz (s), por ejemplo:

public interface IFoo { 
    [CacheDuration(20)] // cache for 20 minutes 
    string[] DoSomethingReusable(); 

    SomeType DoSomethingNonReusable(int key); // not cached 
} 

con la idea de que mediante la adición de una costumbre "convención" a StructureMap 's de barrido (bastante fácil) que puede detectar que uno -o-más métodos están decoradas para el almacenamiento en caché, y automáticamente inyectar un decorador de almacenamiento en caché generada en la tubería de ese tipo (generando una clave de caché a partir de la interfaz/nombre del método y parámetro va lues).

En el lado positivo, hace que agregar el almacenamiento en caché sea muy sencillo, solo decore un poco la interfaz; pero es un olor a código? ¿Y/o estoy duplicando algo que ya está resuelto?

Respuesta

7

Los atributos son bien si tienes en cuenta dos factores importantes:

  • estructura inherentemente descentralizada, en lugar de en un lugar que tenga su rociada sobre metadatos todos y cada uno de los componentes que toca

  • estructura constante del compilador rígido. Si de repente decides que la duración de tu caché debe ser 10, no 20, tienes que volver a compilar todo tu código. Podrías enrutar atributos a cosas como config, pero eso está funcionando alrededor de los atributos, y en este punto realmente deberías reconsiderar si usarlos fue la mejor idea en primer lugar.

Siempre y cuando tenga en cuenta estos problemas y los acepte, siga adelante.

+2

+1 Esta respuesta plantea algunos puntos en los que no había pensado. Más munición contra atributos :) –

+0

Re el segundo; para nuestro entorno la reconstrucción de la entidad no es diferente a la reconstrucción del código de nivel superior que registra/configura las cosas. –

+3

podría no serlo, parte importante es que son constantes de tiempo de compilación, con todas las limitaciones que lo acompañan. –

2

El único inconveniente que veo aquí es que no hay un lugar central donde se almacenan los objetos en caché. Por lo general, hay una capa específica donde se realiza el almacenamiento en caché. Con tu técnica, este no es el caso.

También creo que es responsabilidad del código decidir si algo debe almacenarse en caché o no, no el de una clase/interfaz.

Pero para responder a su pregunta, ¿es este un olor a código? Yo diría que no, pero podría ser confuso para los nuevos desarrolladores obtener el truco de este sistema una vez que se utiliza en muchos lugares.

1

No puedo decir que entiendo totalmente todo, pero por mis 2 centavos, parece que está bien; pero me pregunto si es fácil o no cambiarlo sin recompilarlo. Y quizás desee cambiar la duración de la memoria caché a través de la entrada de configuración, y no de una compilación. Probablemente almacenara esos datos en algún lugar donde pueda configurarlos más fácilmente. (Quizás he entendido mal, aunque ...)

+0

Lo que hay allí; * todos * los cambios (code/config/etc) pasan por el mismo proceso (servidor de compilación, validación, etc.); es igual de simple impulsar un cambio de código a través del sistema ya que es un cambio en un archivo de configuración. Excepto en el código, tengo comprobación de tipo estático ;-p –

+0

@Marc Indeed; pero quizás desee cambiarlo mientras se ejecuta (es decir, el valor puede almacenarse en un db?). Supongo que me gustaría tener toda la "configuración" en el mismo tipo de área, luego puedes cambiarla trivialmente. Es decir. si quiere cambiar todos sus 20 a 40, o similar. Justo lo primero que pensé de todos modos. No odio la idea, pero si fuera yo, creo que dejaría que sea configurable en algún lugar (db, si su aplicación subyacente usa uno). –

1

Tiendo a estar de acuerdo con lo que se dijo sobre el almacenamiento en caché tiene que ser decidido por su código, pero otro escenario que veo que es posible que desee tener en cuenta es el "¿Qué necesita ser almacenado en caché, el objeto completo?

Es posible que desee jugar con la idea de tener propiedades para establecer qué miembros no desea almacenar en caché de un objeto.

Tal vez un atributo

[Cache(Duration=20, Location(...))] 

?

+0

Creo que esto se saldrá de control rápidamente (más atributos). En ese caso, será mejor que configure clases específicas para manejar "métodos" específicos de almacenamiento en caché que acepten objetos con varias interfaces que especifiquen cómo desean almacenarse en caché (o algún esquema similar). –

+0

Estoy totalmente de acuerdo :) Gracias por la información. –

5

Por lo que entiendo la pregunta, usted está considerando agregar los atributos para facilitar el registro de contenedores. Aún está implementando los cachés utilizando el patrón de diseño Decorator, que es, IMO, la forma correcta de implementar el almacenamiento en caché.

Hacemos lo mismo en Safewhere, pero en su lugar usamos el registro basado en la convención. También usamos Castle Windsor, así que no sé si esto es posible con StructureMap, pero simplemente escaneamos los ensamblajes apropiados después de cualquier nombre llamado Caching*Repository y los registramos como decoradores para los Repositorios reales. También tenemos una prueba de unidad basada en convenciones que verifica que todos los repositorios de almacenamiento en caché necesarios estén presentes.

Si agregar el atributo personalizado es un olor a código o no depende del grado de reutilización que requiera de su código. Mi regla de oro es que quiero ser poder para conectar todo con Poor Man's DI. Todavía utilizo un DI Container en su lugar, pero esta regla me proporciona un control de cordura.

En general, no me gusta acoplar mi código a un contenedor en particular, pero realmente no puedo averiguar si lo estás haciendo aquí. Depende de si necesita o no hacer referencia a StructureMap para definir el atributo personalizado. Si debe hacer referencia a Structure Map, lo consideraría un olor.

+0

No, el atributo no es específico del contenedor. –

1

Creo que hay algo que considerar cuando se utilizan atributos es el acoplamiento de la intención con la clase. El punto es que no puede usar esa entidad en un solo lugar con una duración de caché de 10 segundos y otro lugar con una duración de caché de 60 segundos. En mi humilde opinión, esta es siempre la compensación con atributos de cualquier tipo.

+0

y como otros han mencionado, Separation of Concerns ... – aaron

1

Llego un poco tarde a la fiesta en este caso, pero he estado pensando en este problema recientemente y, en general, utilizando atributos para el almacenamiento en caché es un código de olor.

Aquí hay un par de razones por las cuales:

  1. almacenamiento en caché de atributo que se puede conseguir en un poco de un escenario de "cola-menear-the-dog", ya que tiene el potencial de cambiar el diseño de su código a medida que implementa métodos que se prestan para ser utilizados por el atributo de almacenamiento en caché, particularmente cuando entra en escenarios complejos.

  2. El almacenamiento en memoria caché por atributo es peligroso porque, aunque el proceso de agregar elementos a la memoria caché generalmente es el mismo (es decir, caché.Añadir (clave, valor)), el proceso de determinar la clave y el elemento que se va a insertar es no siempre es lo mismo y generalmente requiere algún tipo de lógica que no siempre es genérica. Por ejemplo, a menudo se piensa en generar la clave de caché utilizando los valores de los parámetros, pero considere el escenario donde se usa un parámetro de DateTime y el que llama pasa en DateTime.Now ... el valor de retorno siempre será el mismo, pero la clave generada por los parámetros será diferente y generará un nuevo objeto de caché para cada llamada. A continuación, puede cambiar el diseño del método, pero luego de que está recibiendo exactamente en el problema descrito en 1

  3. En términos generales, el almacenamiento en caché se utiliza para optimizar un escenario específico y es raro que la razón es un elemento ingresado en el caché es el mismo.Supongamos que tiene un catálogo de elementos que rara vez cambia, puede decidir cargar todo el catálogo en caché cuando la aplicación se inicia y almacenarlo en caché durante 12 horas, pero puede decidir almacenar en caché los detalles de usuario de un usuario solo después de iniciar sesión. la primera vez. La lógica necesaria para recuperar estos elementos y luego agregarlos a un caché es completamente diferente y no se presta para ser capturado en un atributo.

  4. Si tenía un atributo de caché, también necesitaría una forma de caducar los elementos de caché cuando cambien. Suponiendo que tiene un atributo de caché, lo más probable es que tenga un atributo "CacheExpiry" que tendría los mismos problemas anteriores, pero también tendría que encontrar una forma común de generar claves de caché entre métodos porque Es muy poco probable que sus parámetros para actualizar o eliminar un objeto sean los mismos que para agregar un objeto a la memoria caché.

El fondo es que el almacenamiento en caché de superficie por atributos parece una buena idea, pero en la práctica la naturaleza de los problemas que resuelve el almacenamiento en caché significa que no se presta muy bien a ser conducido por atributos.

Cuestiones relacionadas