Estructura de código para manejar múltiples mercados? (diferentes reglas comerciales para cada estado en los EE. UU.)

8

Estamos desarrollando una aplicación que tiene requisitos ligeramente diferentes para cada mercado empresarial (países y estados) en los que está disponible. Parece una situación común, pero parece que no puedo encontrar un buen artículo sobre la estructuración de código / módulos para este escenario.
Es una aplicación C # y estamos debatiendo entre los patrones de Estrategia vs Plantilla, pero también está la consideración de la estructura de carpetas y las convenciones de nomenclatura. Parece que un proyecto separado para cada estado se volvería inmanejable rápidamente (por ejemplo, 5 servicios básicos X 50 proyectos personalizados por estado) = 250 proyectos !!) ¿Quizás 1 proyecto personalizado por servicio que maneja especializaciones organizadas en subcarpetas por estado?

Kim
fuente
¿Puedes agregar más detalles sobre qué es exactamente diferente entre los estados?
paj28

Respuestas:

8

Tener una sola aplicación y diseñar la solución de configuración adecuada.

JacquesB insinúa esto, pero quiero decirlo con más fuerza. Usted debe hacer esto mediante la configuración en lugar de desarrollar más de 50 versiones del código base. Cualquier otra cosa será increíblemente inmanejable.

Si existen requisitos complejos que no se pueden manejar con parámetros de configuración simples, diseñe una solución de configuración más compleja.

Su configuración podría incluso tener un lenguaje de script simple que defina los requisitos lógicos. Es correcto. La clave es que la "configuración" debe estar limpiamente separada de la base de código de la aplicación.

De lo contrario, cosas como identificar y corregir errores serán un desastre. Con el control de versiones normal además de las versiones específicas de la configuración regional, tendrá cientos de versiones en el campo. Y no podrá saber fácilmente si un error está relacionado con el código específico de la localidad o el código base.

Comience a pensar en casos límite ahora.

Esta es una situación en la que existe un alto riesgo de hacer malas suposiciones que serán increíblemente costosas. Tales como "Cada usuario de la aplicación solo necesitará operar dentro de un entorno local". ¿Es eso cierto? Asegúrate de pensar mucho en estos temas lo antes posible.


fuente
Estamos configurando una solución de configuración usando AutoFac Multitenancy. ¿Algún consejo para organizar y nombrar los componentes (clases / proyectos)?
Kim
Si. Iba a comentar que este es un gran ejemplo para la inyección de dependencia. Puede definir la interfaz común y crear componentes específicos que luego se pasan según alguna configuración. Esto debería permitir una mejor capacidad de prueba y mantenimiento que las secuencias de comandos personalizadas como se menciona en otra respuesta.
Fran
6

Realmente depende de lo que sea ​​diferente. ¿Es algo que puede expresarse únicamente por configuración (por ejemplo, tasas de impuestos), o realmente necesita una lógica de código separada para cada estado? ¡Cuanto más pueda manejar puramente por configuración, mejor!

Lo más probable es que no necesite un código separado por estado. Por ejemplo, usted menciona que algunos mercados emiten reembolsos mientras que otros emiten reemplazos. Esto sigue siendo solo dos rutas de código que debe probar. Entonces puede hacer que una configuración indique qué ruta se debe usar para qué estado. Esto es mucho mejor que tener un código separado para cada estado. Todavía solo necesita probar dos rutas de código con una calificación de 50.

Si alguna vez siente la necesidad de escribir código individual para cada uno de los 50 estados, probablemente lo esté haciendo mal. Definitivamente no debe tener proyectos separados por estado, o incluso tener "50 diferentes" de cualquier cosa, excepto las secciones de configuraciones.

JacquesB
fuente
Es más que solo impuestos, pero el alcance de las diferencias es desconocido en este momento. También estamos tratando con múltiples países. Hay flujos de trabajo que también pueden ser ligeramente diferentes, como algunos mercados que reembolsan las compras, mientras que otros emiten reemplazos. Y ciertamente precios diferentes por mercado.
Kim
A lo que JacquesB está llegando es a abstracciones. IOW, ¿cómo podrían ser diferentes las cosas que parecen diferentes? "Todos los estados cobran impuestos" Ahora tengo un concepto general que puedo codificar universalmente: "CalcTax ()". Y todo lo que necesita son las tasas de impuestos específicas (tabla de impuestos), es decir, la configuración. Escúcheme ahora y créame más tarde, "datos de configuración": ¡el concepto abstracto! - simplificará enormemente el código.
radarbob
Si hay mucha superposición en la funcionalidad entre los estados (más allá de una opción "predeterminada" efectiva), este es un buen consejo. Si los estados son propensos a matices que hacen que sea difícil / peligroso agruparlos como una especie de "Opción B", no lo es. El OP necesitará resolver eso. También existe el peligro de dolor de cabeza si un estado aprueba nuevas leyes que obligan a las actualizaciones de código, pero eso será cierto para cualquier condición en la que varios estados estén usando el mismo código.
BlairHippo
5

He tenido alguna experiencia práctica con tales proyectos, y al menos puedo ofrecer algunas pautas generales.

  • JacquesB tiene toda la razón en que la configuración es su mejor amigo. Si coloca esa configuración en archivos o en tablas de bases de datos es una opción estilística (aunque me inclinaría por los archivos de configuración, ya que una vez que configure un servicio, estoy dispuesto a apostar que no cambiará mucho).

  • Espere un código que parezca mucho más indirecto de lo que probablemente esté acostumbrado. Habrá muchos lugares donde, en lugar de decir "Haz esto a continuación", dirás "Pregunta a la configuración qué se supone que debemos hacer a continuación, luego ve a hacer eso". Lo cual puede ser un dolor de cabeza de desarrollo, pero te acostumbrarás.

  • Recomendaría una estructura de "Estos son los elementos comunes que probablemente todos quieran, y estos son los elementos a medida diseñados a mano para estados individuales". Con ese fin, identificar correctamente esa funcionalidad predeterminada será una gran parte de cuán fácil / horrible será trabajar con el código en el futuro. Esté preparado para refactorizar cuando aprenda que es necesario configurar más cosas de las que pensaba.

  • Asegúrese siempre de que los mensajes de error provenientes de los elementos personalizados identifiquen exactamente de dónde provienen. La gran cantidad de rutas de ejecución diferentes significan que la depuración será una mierda, pase lo que pase; todo lo que pueda hacer para reducir la cantidad de caza de huevos de Pascua será más que valioso.

  • Invierta el tiempo para hacer un buen conjunto de pruebas automatizadas. Un conjunto de pruebas automatizado MUY bueno. Esto siempre es una buena práctica, pero para usted, literalmente, podría significar la diferencia entre el éxito y el fracaso. De nuevo, es la gran variedad de rutas de ejecución; Cualquier modificación al código común lo hará vulnerable a los errores de efecto mariposa en las ramas que no esperaba. Necesitas atrapar esos errores antes de que lleguen a producción.

BlairHippo
fuente
Gracias. ¿Alguna sugerencia para nombrar clases, agrupar proyectos? ¿Deberían las implementaciones tener el sufijo con el nombre del mercado o intentar describir las diferentes funcionalidades?
Kim
No soy un chico de ac #, así que no puedo hablar sobre cómo nombras las clases. Pero, sinceramente, creo que querrías un nombre de paquete que incorpore tanto el mercado como la funcionalidad, para que puedas decir de un vistazo lo que se supone que debe hacer. Algo así como ourproject.calculations.taxpor defecto y ourproject.florida.calculations.taxpara cualquier modificación personalizada que la ley de Florida le impuso (si la hubiera). Donde pones ese nombre de mercado es un punto de discusión, pero me inclinaría por facilitarle ver qué personalizaciones le está imponiendo un mercado en particular.
BlairHippo
2

Aunque config puede ayudarlo, no va a resolver todos sus problemas y puede crear otros nuevos.

Con mucho, la mejor manera en mi experiencia es crear una solución multi inquilino que pueda manejar todos o cualquiera de los estados (inquilinos)

Esto requerirá configuración. es decir, porcentaje de impuesto a las ventas por estado pero también código condicional LegalMethodOfCalculatingWorkingHoursA vs B

Si su aplicación está alojada / en línea, podría adoptar un enfoque de microservicios para el código condicional, pero una solución fuera de línea tendrá que agrupar todos los módulos opcionales y seleccionar entre ellos.

Encontrará algunos módulos reutilizados en todos los estados, como el impuesto a las ventas y algunos leyes locas que solo se usan en un solo estado. También encontrará que las leyes cambian con el tiempo. por lo que los módulos utilizados variarán según el tiempo dentro de un solo estado

Así que iría con los nombres por funcionalidad en lugar de estado.

Ewan
fuente
Me gusta esto: las ramas de código se basan en la funcionalidad, por ejemplo, "debe pedir dirección", "la entrega está exenta de impuestos". Luego, la configuración para eso asigna cada estado a un conjunto de funcionalidades.
paj28