2009-08-26 10 views
9

Estamos planeando crear un marco: un marco de estimación de costos que se utilizará en todos los dominios de nuestra organización.Aspectos a tener en cuenta al crear un marco

El requisito de alto nivel es algo como esto: Si desarrollo cierto producto, ¿cuánto me va a costar? Este costo generado se usará para comparar con el costo que los proveedores han cotizado y para decidir qué proveedor elegir.

Ahora, mi pregunta es: ¿Qué cosas considerar al desarrollar un marco?

Pocos de mis pensamientos:

  1. implementar los requisitos de alto nivel a través de clases abstractas e interfaces
  2. ofrecen clases de servicios públicos que podrían ser útiles para los usuarios del programa marco.
  3. Considere lo que debería ser interno, tipo de metadatos, que no deberían mostrarse a los usuarios del framework.
  4. Los patrones de diseño para usar como plantilla.
  5. las propiedades y los métodos de las clases de entrada.

Respuesta

13

algunas ideas:

  • Es más fácil añadir funciones útiles más tarde de eliminar características que han demostrado ser mal diseñado o perjudicial.
  • Diseñe para heredar o prohibirlo: la herencia presenta una capa adicional de complejidad, ya que necesita resolver las interacciones entre las superclases y las subclases. Eso no quiere decir que sea malo, pero debería ser muy cuidadosamente considerado.
  • Las interfaces son generalmente más limpias que las clases abstractas en mi experiencia, ya que promueven la composición sobre la herencia.
  • Para las interfaces, documente lo que la persona que llama debe esperar y lo que el implementador debe esperar. Básicamente piense en el contrato de ambos lados y documentelo. En particular, las restricciones de nulidad del documento: ¿deben los métodos aceptar nulo o no? ¿Deberían garantizar que nunca regresarán nulos?
  • Diseño para la capacidad de prueba, tanto de su marco como de otros que utilizan su marco. ¿Qué partes del marco se pueden usar razonablemente en el código de prueba y cuáles deberían ser burladas?
  • Use su propio marco, desde el principio. Cree una aplicación de muestra que otros puedan usar para comprender el marco.
+0

También agregaría prefiera la inyección de dependencia a la instanciación directa/búsqueda de servicio (aunque el diseño para la capacidad de prueba normalmente lo exige). –

+0

+1 para mantenerlo lo más simple posible. –

+2

Solo para dar un argumento de contador. Para los marcos que evolucionan rápidamente (y, por lo tanto, los más nuevos), el uso de interfaces a menudo se discute. Consulte "Las interfaces están sobrevaluadas" - http://www.artima.com/weblogs/viewpost.jsp?thread=142428 – Pablojim

2

Así es como yo procedo:

  1. hacer un diseño amplio de alto nivel - cosas como se trata de una aplicación Web o cliente pesado, hay un nivel medio, ¿cómo será la interacción DB sucederá, qué API/tecnologías se usarán, etc.
  2. elija una característica que le permita codificar todos los niveles de la aplicación (lo que comúnmente se conoce como pico).
  3. implemente el mínimo indispensable para que esa característica funcione (Keep It Simple, Stupid) junto con las pruebas para demostrar que funciona.
  4. elija otra característica goto 3 (refactorización según sea necesario).

Siempre he encontrado que esta manera de trabajar evoluciona el sistema y que realmente hacer algo funciona enfoca su diseño en lo esencial (en lugar de los vuelos de fantasía que pueden suceder con diseños de papel).

Y no era yo pensando que el agilist en mí se había ido ;-)

2

Aparte de los consejos generales de programación, es digno de mirar en algunos de los conceptos básicos de la teoría de diseño de la estructura de software. Para empezar, examine el concepto de "puntos calientes" y "puntos congelados". Si bien esto puede no parecer inmediatamente útil, es bueno tenerlo en mente mientras se desarrolla.

Como siempre Wikipedia es un buen punto de partida:

http://en.wikipedia.org/wiki/Software_framework

también un buen resumen aquí:

http://www.acm.org/crossroads/xrds7-4/frameworks.html

Si quieres profundizar más echar un vistazo a las citas en ambos estos artículos.

0

Usa interfaces en contratos de API. Esto le permite mantener los detalles desordenados completamente desacoplados y decorarlos fácilmente si es necesario. (Solo ve Propiedades que son Mapas poco disimulados).

Un consejo muy bueno es utilizar Test Driven Design, es decir, escribir la prueba FIRST y luego la implementación. Esto te obliga a pensar como los USUARIOS en lugar del diseñador, lo que eventualmente te conducirá a una mejor API.

6

Algunos de los consejos a continuación dependen de si está construyendo un marco estrictamente para uso interno de un pequeño equipo en un conjunto limitado de proyectos, o si está creando algo para el uso de muchos desarrolladores anónimos. Además, tenga en cuenta que mucho depende del tamaño de su marco y cuán amplio o estrecho es su alcance. Algunos de mis consejos realmente solo se aplican a marcos más grandes y de propósitos múltiples.

Consejo general

  • toma el tiempo para hablar con algunos de los desarrolladores que va a utilizar el marco. Asegúrese de comprender realmente lo que será útil y lo que no.
  • Tómese el tiempo para asegurarse de que la abstracción que está creando sea comprensible e intuitiva para sus futuros usuarios.
  • A menos que esté creando algo único y revolucionario, tómese el tiempo para mirar otros marcos que existen en su dominio. Evite sus errores, pero no tema pedir prestados conceptos exitosos ... no todo tiene que ser inventado por usted.
  • Produce documentación - tanto en forma de documentos API formales como en código de muestra. Si las personas no pueden entender cómo aplicar su marco, no tendrá éxito.
  • Nombre las cosas de forma clara pero concisa. Esta es probablemente una de las tareas más difíciles para los desarrolladores de frameworks, especialmente cuando se implementan conceptos abstractos o generalizados.Hable con la gente antes de decidirse por un nombre ... algunos nombres tienen múltiples significados y pueden interpretarse de manera diferente a lo que cabría esperar.
  • Considere hacer que su marco sea compatible con otras estructuras de bajo nivel (como las de registro, burla e inyección de dependencia). Esto hará felices a los usuarios y reducirá las barreras a la adopción.
  • Invierta en buenas pruebas unitarias. Los marcos generalmente tienen una gran área de superficie con la que los usuarios pueden interactuar ... muchas clases, muchos métodos, derivación, implementaciones de interfaz. Sin una capacidad de prueba de regresión rápida, los marcos pueden crecer rápidamente más allá de un nivel donde se pueden mantener.
  • Mantenga sus interfaces públicas estrechas y pequeñas. Tenga en cuenta el principio de responsabilidad única al diseñar la funcionalidad en un marco ... realmente importa en este nivel.

Diseño Consejo

  • diseño y test de paralelismo. La mayoría de los marcos en estos días se utilizan para crear aplicaciones con algunas (y muchas) actividades paralelas de procesamiento. Los marcos destinados a ser utilizados en aplicaciones web, especialmente, necesitan una cuidadosa reflexión sobre cómo les afectará el acceso multiproceso. Algunos principios generales que sigo son:
    • Evite los bloqueos cuando sea posible. Cuando no sea posible, utilice objetos de bloqueo explícitos en lugar de instrucciones de bloqueo .NET (...).
    • Use los bloqueos de lector/escritor para objetos compartidos que se leen con más frecuencia que los escritos.
  • Funcionalidad de diseño en capas. Para marcos grandes, esto ayuda no solo a mantener la funcionalidad desacoplada, sino que también permite a los usuarios utilizar más fácilmente solo la parte de su marco que realmente necesitan.
  • Para los marcos destinados para uso con .NET 2.0 y versiones posteriores, ¡utilice colecciones genéricas! Es extremadamente difícil razonar sobre lo que se almacena en un objeto [], ArrayList o Hashtable ... especialmente en un marco grande donde dichas colecciones se transfieren internamente.
  • Evite el uso de objetos u objetos [] en la interfaz pública ... esto es malo en un marco y es una causa principal de errores y problemas de mantenimiento. Casi siempre puedes encontrar una interfaz o usar genéricos en lugar de esto. En esos raros casos, no puede, documento exactamente lo que espera que se transfiera o entregue ... y afirme por ello.
  • Prefieren la agregación a la herencia. Si bien la herencia es un concepto útil y poderoso, los autores de los marcos a menudo usan o usan mal. Piense detenidamente sobre si la herencia es verdaderamente la herramienta adecuada para resolver un problema de diseño.
  • Evite los vaciados de tipo y los controles del tipo de tiempo de ejecución cuando sea posible. Estos son generalmente un olor de diseño en mi experiencia. El lote de fundición indica que no está aprovechando las interfaces, los genéricos o las restricciones genéricas de manera efectiva. Esto puede llevar a errores y confusión por parte de los desarrolladores en cuanto a cómo usar su marco.
  • Permita que las personas que llaman inserten la funcionalidad usando estrategias cuando sea posible. La herencia es exagerada para ciertos tipos de especialización. Con el nivel de funciones de soporte que obtienen los ciudadanos en la ecología .NET, debería utilizarlos (en forma de lambdas o delegados) para permitir a los consumidores especializar la funcionalidad que proporciona.

asesoramiento sobre la ejecución

  • propiedades Evita cuyos captadores producir efectos secundarios. A veces esto es inevitable (como los captadores que realizan el almacenamiento en caché interno o los objetos instantaneos perezosamente). Sin embargo, en mi experiencia, getters con efectos secundarios (particularmente en código de nivel de marco) es la forma más rápida de introducir heisenbugs y hacer que tus usuarios maldigan tu nombre cuando depuran.
  • Cuando sea posible, haga que los objetos pequeños y transitorios sean inmutables. Haga cumplir esto utilizando la palabra clave readonly (o equivalente) en el idioma. Los beneficios para la inmutabilidad son enormes, y en .NET (donde los costos de asignación son reducidos) no es tan caro como podría pensar.
  • Use self-encapsulation cuando sea posible. Esta técnica ayuda a evitar errores y simplifica la refactorización al evitar diferentes semánticas de acceso a los datos para los llamantes internos y externos.
  • Evite los números mágicos y las constantes codificadas. Un marco es un tipo de código en el que es muy difícil anticipar las necesidades exactas de los usuarios. Deje algo de flexibilidad mediante el uso de la configuración en lugar de constantes compiladas.
  • Mantenga la cantidad de parámetros para métodos pequeños (menos de 7). Cuando necesite pasar muchos parámetros, considere crear un objeto de datos liviano para admitir el método.
  • Prefieren los métodos genéricos a múltiples sobrecargas de métodos para diferentes tipos. Deje que el lenguaje y el compilador hagan el trabajo cuando sea posible. Esto también permite que su código sea más flexible y útil. Examine el diseño de LINQ para ver cómo funciona esto en la práctica.
Cuestiones relacionadas