10

Estoy buscando algunos consejos sobre cómo permitir una fácil personalización y extensión de un producto central por cliente. Sé que es probablemente una gran pregunta. Sin embargo, realmente necesitamos obtener algunas ideas, como si obtuviéramos la configuración de este error, nos podría causar problemas durante años. No tengo mucha experiencia en personalizar y extender productos existentes.¿Cuál es una buena estructura de solución para permitir una fácil personalización de un producto por cliente?

Tenemos un producto principal que generalmente especificamos por cliente. Recientemente hemos reescrito el producto en C# 4 con un frontend MVC3. Hemos rediseñado y ahora tienen 3 proyectos que componen la solución: (. Espacio de nombres - projectname.domain *) -

  • proyecto básico de dominio que consiste en modelos de dominio (para su uso por EF), interfaces de servicio de dominio, etc (interfaces de repositorio)
  • proyecto de infraestructura
  • de dominio (-projectname.infrastructure espacio de nombres *) -. que implementa el contexto de dominio de servicio-EF, la implementación del repositorio, carga/descarga de interfaz implementaciones etc.
  • MVC3 (espacio de nombres -. projectname.web *) -proyecto que consiste en controladores, viewmodels, CSS, contenido, scripts, etc. También tiene IOC (Ninject) manejando DI para el proyecto.

Esta solución funciona bien como un producto independiente. Nuestro problema es ampliar y personalizar el producto por cliente. Por lo general, nuestros clientes desean que les enviemos la versión del producto principal de manera muy rápida (por lo general, dentro de los dos días posteriores a la firma de un contrato) con CSS y estilo de marca. Sin embargo, el 70% de los clientes quiere que las personalizaciones cambien su funcionamiento. Algunas personalizaciones son pequeñas, como propiedades adicionales en el modelo de dominio, modelo de vista y vista, etc. Otras son más significativas y requieren controladores y modelos de dominio completamente nuevos.

Algunas personalizaciones parecen ser útiles para todos los clientes, por lo que periódicamente nos gustaría para cambiarlos de ser personalizaciones y agregarlos al núcleo.

Actualmente estamos almacenando el código fuente en TFS. Para comenzar un proyecto, normalmente copiamos manualmente la fuente en un nuevo proyecto de equipo. Cambie el espacio de nombre para reflejar el nombre del cliente y comience a personalizar las partes básicas y luego impleméntelo en Azure. Obviamente, esto resulta en una base de código completamente duplicada y estoy seguro de que no es la forma correcta de hacerlo. Creo que probablemente deberíamos tener algo que proporcione las características principales y amplíe/sustituya cuando sea necesario. Sin embargo, no estoy seguro de cómo hacerlo.

por lo que estoy buscando algún consejo sobre la mejor configuración del proyecto que permitiría:

  • Rápida implementación del código - tan fácil para empezar un nuevo cliente para permitir marca/cambios menores
  • evitar la necesidad de copiar y pegar el código de
  • el uso de DI tanto como sea posible para mantenerlo imprecisa
  • permitir la bespoking del código en una base por cliente
  • La capacidad de extender el producto principal en un solo lugar y tienen todos los clientes a obtener esa funcionalidad si tenemos la última versión del núcleo y volver a desplegar

Cualquier ayuda/consejo es muy apreciada. Feliz de agregar más información que cualquiera piense que ayudará.

+0

Después de intentar la bifurcación por cliente para 5 proyectos, nos damos por vencidos. Ahora lo hemos escrito como un producto único que utiliza MEF y DI para unirlo según la configuración del cliente. También significa que podemos implementarlo en un único servidor web y escalar mejor. – GraemeMiller

+0

Vea esto en multi-tenancy que cubre la situación http://codeofrob.com/entries/multi-tenancy-in-asp.net-mvc---ddd8-video.html – GraemeMiller

Respuesta

4

I just worried that with 30 or 40 versions (most of which aren't that different) branching was adding complexity.


+1 Muy buena pregunta, que es más bien una decisión de negocios que tendrá que hacer:

¿Quiero una base de código limpio donde el mantenimiento es fácil y características y correcciones de conseguir extenderá rápidamente a todos nuestros clientes

o quiero una gran cantidad de casos de un solo código base dividida, cada uno con pequeños retoques que es difícil (EDIT: no ser que un ALM MVP que puede cosas "unbrand") a se fusionó en un tr unk


Estoy de acuerdo con casi EVERTHING @Nockawa mencionado, excepto en mi humilde opinión dont sustituto de la ampliación de su arquitectura de código con ramas.

Definitivamente utilice una estrategia de bifurcación/troncal pero como mencionó demasiadas ramas hace que sea más difícil ampliar quickly características del sitio de despliegue y obstaculizar la integración continua en todo el proyecto. Si desea evitar copiar/pegar, limite el número de ramas.

En términos de una solución de codificación que aquí es lo que creo que busca:

  • Módulos/Plugins, interfaces y DI es justo en el blanco!
  • Derivación de clases personalizadas fuera de las bases (extendiendo el DSL por cliente, Assembly.Load)()
  • solución de informes personalizada (en lugar de nuevas páginas una gran cantidad de peticiones de la aduana podría ser informes)
  • Las páginas con hojas de cálculo (jeje yo sé - pero curiosamente funciona)

Grandes ejemplos del punto/módulo plug-in son de CMS como DotNetNuke o Kentico!. Se pueden obtener otras ideas mirando la arquitectura de complementos de Facebook, los complementos para edición de audio y video, las aplicaciones de modelado 3D (como 3DMax) y los juegos que le permiten crear sus propios niveles.

La solución ideal sería una aplicación de administración que podrá seleccionar el módulos (DLL), adaptar el CSS (piel), la escritura del dB, y auto-desplegar la solución hasta Azure. Para lograr este objetivo, el plugin haría que tenga mucho más sentido, la base de código no se dividirá. Además, cuando se realiza una mejora de en un módulo, puede desplegarlo en todos sus clientes .

Puede realizar fácilmente pequeñas personalizaciones, como propiedades adicionales en el modelo de dominio, el modelo de vista y vista, etc. con controles de usuario, clases derivadas y anulaciones de funciones.

Hágalo de forma muy genérica, digamos que un cliente dice que quiero una etiqueta que indique la edad de todos en el sistema, realice una función llamada int SumOfField(string dBFieldName, string whereClause) y luego, para ese sitio de clientes, tenga una etiqueta que vincule a la función. Luego, indique que otro cliente desea que una función cuente la cantidad de compras de productos por cliente, puede volver a usarla: SumOfField ("product.itemCount", "CustomerID = 1").

Cambios más significativos que requieren modelos de dominio y controladores totalmente nuevos, etc. se adaptarían a la arquitectura del complemento. Un ejemplo podría ser que un cliente necesita un segundo campo de dirección, modificaría su actual Dirección de usuario de control para que sea un complemento de cualquier página, tendría una configuración para saber qué tabla de dB y qué campos puede implementar su interfaz para las operaciones de CRUD. .

Si la funcionalidad es personalizado por cliente en 30-40 ramas mantenimiento llegará a ser tan duro como me da la sensación que no será capaz de unirlos (fácilmente). Si existe la posibilidad de que esto sea realmente grande, no desea administrar 275 sucursales. Sin embargo, si es que se especializó, tiene que bajar al nivel de Control de usuario para cada cliente y "los usuarios no pueden diseñar sus propias páginas" teniendo La estrategia de bifurcación de Nockawa para el front-end es perfectamente razonable.

+1

Gran respuesta también. Voy a tomar ambos enfoques, creo. Estoy buscando en Orchard inspiración sobre cómo hacer que la aplicación sea modular. Voy a escribir otra pregunta sobre eso y probablemente le pondré una recompensa.Inicialmente, me estoy centrando en la bifurcación, ya que es el lugar más simple para comenzar, ya que solo tenemos unos pocos clientes que se trasladan a la nueva base de códigos. Una vez que vea dónde están sucediendo las divergencias, intentaré convertir esas partes en módulos y luego ramificarlos, etc. – GraemeMiller

+0

Después de 5 clientes con el enfoque ramificado, nos damos por vencidos. Fue una pesadilla. Nuestro producto central cambiaba constantemente y requería fusiones constantes. Estamos implementando un enfoque modular usando DI y también usando MEF. Estamos implementando que es un producto único y que la configuración informe qué módulos/personalizaciones se incluyen. Fue mucho más fácil. Solo requiere pensar un poco más en el diseño. – GraemeMiller

8

puedo no responder a esta completamente, pero aquí algunos consejos:

  1. No copie su código, siempre, cualquiera que sea la razón es.
  2. No cambie el nombre del espacio de nombres para identificar una versión de cliente determinada. Usa las ramas y la integración continua para eso.
  3. Elija un modelo de bifurcación como el siguiente: una rama raíz llamada "Principal", luego cree una rama desde Principal por versión principal de su producto, luego una rama por cliente. Cuando desarrolles algo, apunta desde el principio en qué rama desarrollarás según lo que estés haciendo (una característica específica del cliente irá en la rama del cliente, una versión global en la rama de la versión o del cliente si quieres crear un prototipo al principio, etc.)
  4. Intente lo mejor para confiar en el elemento de trabajo para rastrear las características que desarrolla para saber en qué rama se ha implementado para facilitar la fusión entre sucursales.

Dirigirse a la rama correcta para su desarrollador es lo más importante, no tiene que definir necesariamente algunas reglas duras de "qué hacer en qué ocasión", pero trate de ser constante.

He trabajado en un gran proyecto de 10 años con más de 75 versiones y lo que hizo fue por lo general:

  • versión principal Siguiente: Crear una nueva rama de la principal, dev Dentro
  • Siguiente menor versión: dev en la rama principal actual, use etiquetas para marcar cada versión menor dentro de su rama.
  • Algunas funciones funcionales complejas se desarrollaron en la rama del cliente que las solicitó, y luego se invierten integradas en la rama de versión cuando logramos "sin nombre".
  • Corrección de errores en la rama del cliente, luego se informa en otras ramas cuando es necesario. (debe usar el elemento de trabajo para eso o se perderá fácilmente).

Es mi opinión, otros pueden tener un punto de vista diferente, confié mucho en el elemento de trabajo para la trazabilidad del código, lo que me ayudó mucho en la entrega y el informe del código.

EDITAR

Ok, añadir un poco de pensamiento/comentarios acerca de ramas:

En Software Configuration Management (SCM) que tienen dos características que le ayudarán a versionning: ramas y etiquetas. Cada uno no es mejor ni peor que el otro, depende de lo que necesita:

  1. Una etiqueta se utiliza para marcar un punto en el tiempo, el uso de una etiqueta, para que pueda ser más tarde capaz de volver a ese señalar si es necesario.
  2. Una rama se utiliza para "duplicar" su código para poder trabajar en dos versiones al mismo tiempo.

El uso de las ramas solo depende de lo que desee hacer. Si tiene que trabajar con muchas versiones diferentes (digamos una por cliente) al mismo tiempo: no hay otra manera de tratar con eso que usar las ramas.

Para limitar el número de sucursales que tiene que decidir lo que será una nueva rama o lo estará marcada por una etiqueta para: versiones específicas del cliente, la versión principal, versión menor, Service Pack, etc.

Uso las sucursales para las versiones de Cliente parecen ser obvias. Usar una rama para cada versión Major puede ser la elección más difícil para ti. Si elige usar solo una rama para todas las versiones principales, entonces no tendrá la flexibilidad de trabajar en diferentes versiones principales al mismo tiempo, pero su número de sucursales será el más bajo posible.

Finalmente, Jemery Thompson tiene un buen punto cuando dice que no todo el código debe depender del cliente, hay algunas bibliotecas (generalmente las de nivel más bajo) que no deben personalizarse por cliente. Lo que hacemos generalmente es utilizar un árbol de ramificación separado (que no es por cliente) para las bibliotecas de servicios de Framework, transversales y de bajo nivel. Luego haga referencia a estos proyectos en los proyectos de la versión por cliente.

Mi consejo para usted es usar Nuget para estas bibliotecas y crear el paquete nuget para ellas, ya que es la mejor manera de definir dependencias versionadas. Definir un paquete Nuget es realmente fácil, así como también configurar un servidor Nuget local.

+0

Gracias por su respuesta. Veo que la bifurcación tiene sentido. Si no cambio el espacio de nombres para identificar la versión del cliente, entonces sería mucho más fácil. Por alguna razón, me imaginé un núcleo que heredaba versiones a medida. Bien podría ser que simplemente ramificar y volver a integrar las personalizaciones en el núcleo simplemente tenga más sentido. Me preocupaba que con 30 o 40 versiones (la mayoría de las cuales no son tan diferentes), la bifurcación estaba agregando complejidad. – GraemeMiller

+2

Las sucursales no cuestan tanto en TFS, por lo que su única preocupación es cómo administrar la cantidad de manera eficiente. – Nock

+1

+1 buen resumen a una buena pregunta –

Cuestiones relacionadas