Estrutura de código para lidar com vários mercados? (regras comerciais diferentes para cada estado nos EUA)

8

Estamos desenvolvendo um aplicativo com requisitos ligeiramente diferentes para cada mercado comercial (países e estados) do qual ele está disponível. Parece uma situação comum, mas não consigo encontrar um bom artigo sobre a estruturação de códigos / módulos para esse cenário.
É um aplicativo C # e estamos debatendo entre os padrões Estratégia versus Modelo, mas há também a consideração da estrutura de pastas e das convenções de nomenclatura. Parece que um projeto separado para cada estado se tornaria incontrolável rapidamente (por exemplo, 5 serviços principais X 50 projetos personalizados do estado) = 250 projetos !!) Talvez 1 projeto personalizado por serviço que lide com especializações organizadas em subpastas por estado?

Kim
fonte
Você pode adicionar mais detalhes sobre o que exatamente é diferente entre os estados?
paj28

Respostas:

8

Tenha um único aplicativo e crie a solução de configuração apropriada.

JacquesB sugere isso, mas quero afirmar com mais força. Você deve fazer isso por configuração, em vez de desenvolver mais de 50 versões da base de código. Qualquer outra coisa será insanamente incontrolável.

Se houver requisitos complexos que não possam ser manipulados por parâmetros de configuração simples, projete uma solução de configuração mais complexa.

Sua configuração pode até ter uma linguagem de script simples que define os requisitos lógicos. Está bem. A chave é que a "configuração" deve estar bem separada da base de código do aplicativo.

Caso contrário, coisas como identificar e corrigir bugs serão uma bagunça. Com a versão normal, além das versões específicas do código do idioma, você terá centenas de versões no campo. E você não será capaz de dizer com facilidade se um bug está relacionado ao código específico da localidade ou ao código base.

Comece a pensar em casos extremos agora.

Essa é uma situação em que há um alto risco de fazer suposições ruins que serão incrivelmente caras. Como "Cada usuário do aplicativo só precisará operar em um local". Isso é verdade? Certifique-se de pensar muito sobre esses problemas o mais cedo possível.


fonte
Estamos instalando uma solução de configuração usando o AutoFac Multitenancy. Algum conselho sobre como organizar e nomear os componentes (classes / projetos)?
28416 Kim
Sim. Eu ia comentar que este é um ótimo exemplo para injeção de dependência. Você pode definir a interface comum e criar componentes específicos que são passados ​​por alguma configuração. isso deve permitir uma testabilidade e manutenção muito melhores do que o script personalizado, como mencionado em outra resposta.
Fran
6

Realmente depende do que é diferente. É algo que pode ser expresso puramente pela configuração (por exemplo, taxas de imposto) ou você realmente precisa de uma lógica de código separada para cada estado? Quanto mais você puder lidar exclusivamente com a configuração, melhor!

Você provavelmente não precisa de código separado por estado. Por exemplo, você menciona que alguns mercados emitem reembolsos enquanto outros substituem. Ainda são apenas dois caminhos de código que você precisa testar. Em seguida, você pode ter uma configuração indicando qual caminho deve ser usado para qual estado. Isso é muito melhor do que ter um código separado para cada estado. Você ainda precisa testar apenas dois caminhos de código com mais de 50.

Se você sentir necessidade de escrever um código individual para cada um dos 50 estados, provavelmente está fazendo algo errado. Definitivamente, você não deve ter projetos separados por estado, ou mesmo ter "50 diferentes" de qualquer coisa, exceto as seções de configurações.

JacquesB
fonte
é mais do que apenas tributação, mas a extensão das diferenças é desconhecida no momento. Também estamos lidando com vários países. Existem fluxos de trabalho também que podem ser ligeiramente diferentes, como alguns mercados reembolsam compras enquanto outros emitem substituições. E certamente preços diferentes por mercado.
Kim
O que JacquesB está entendendo são abstrações. IOW, como as coisas que parecem diferentes podem realmente ser as mesmas? "Todos os estados cobram impostos" Agora, tenho um conceito geral que posso codificar universalmente: "CalcTax ()". E tudo o que você precisa são as taxas de imposto específicas (tabela de impostos) - ou seja, a configuração. Ouça-me agora e acredite em mim mais tarde, "dados de configuração" - o conceito abstrato! - simplificará bastante o código.
Radarbob 29/10/16
Se houver muita sobreposição na funcionalidade entre os estados (além de uma opção "padrão" efetiva), este é um bom conselho. Se os estados são propensos a nuances que tornam difícil / perigoso agrupá-los como uma espécie de "Opção B", não é. O OP precisará descobrir isso. Também existe o risco de dor de cabeça caso um estado aprova novas leis forçando atualizações de código, mas isso será válido para todas as condições em que vários estados estiverem usando o mesmo código.
BlairHippo
5

Eu tive alguma experiência prática com esses projetos e posso pelo menos oferecer algumas diretrizes gerais.

  • JacquesB está absolutamente certo de que a configuração é sua melhor amiga. Se você coloca essa configuração em arquivos ou em tabelas de banco de dados, é uma opção estilística (embora eu esteja inclinado a arquivos de configuração, pois uma vez que você cria um serviço, estou disposto a apostar que isso não mudará muito).

  • Espere um código que pareça muito mais indireto do que você provavelmente está acostumado. Haverá muitos lugares onde, em vez de dizer "Faça isso a seguir", você estará dizendo "Peça à configuração o que devemos fazer a seguir e depois faça isso". O que pode ser uma dor de cabeça no desenvolvimento, mas você vai se acostumar.

  • Eu recomendaria uma estrutura de "Esses são os elementos comuns que todo mundo provavelmente deseja, e esses são os elementos personalizados, desenhados à mão para estados individuais". Para esse fim, identificar corretamente essa funcionalidade padrão será uma grande parte de quão fácil / terrível o código é trabalhar no futuro. Esteja preparado para fazer alguma refatoração quando descobrir que mais coisas do que você pensava precisam ser configuráveis.

  • Sempre verifique se as mensagens de erro provenientes dos elementos personalizados identificam exatamente de onde elas vieram. O grande número de caminhos de execução diferentes significa que a depuração será péssima, não importa o quê; qualquer coisa que você possa fazer para reduzir a quantidade de caça aos ovos de páscoa valerá a pena.

  • Invista tempo para criar um bom conjunto de testes automatizados. Um conjunto de testes automatizado MUITO bom. Essa é sempre uma boa prática, mas, para você, pode significar literalmente a diferença entre sucesso e fracasso. Novamente, é a enorme variedade de caminhos de execução; quaisquer modificações no código comum o deixarão vulnerável a bugs com efeito borboleta em ramos que você não esperava. Você precisa capturar esses bugs antes que eles atinjam a produção.

BlairHippo
fonte
Obrigado. Alguma sugestão para nomear classes, agrupar projetos? As implementações devem ter o sufixo do nome do mercado ou tentar descrever as diferentes funcionalidades?
Kim
Eu não sou um cara #, então não posso falar com detalhes de como você nomeia classes. Mas, honestamente, eu acho que você gostaria de um nome de pacote que incorpore o mercado E a funcionalidade, para que você possa ver rapidamente o que ele deve fazer. Algo parecido ourproject.calculations.taxcom o padrão e ourproject.florida.calculations.taxcom os mods personalizados que a lei da Flórida impôs a você (se houver). Onde você coloca esse nome de mercado é um ponto de discussão, mas eu gostaria de facilitar a visualização de quais personalizações um determinado mercado está impondo a você.
BlairHippo
2

Embora a configuração possa ajudar a não resolver todos os seus problemas, ela pode criar novos.

De longe, a melhor maneira na minha experiência é criar uma solução de multilocação que possa lidar com todos ou com qualquer um dos estados (inquilinos)

Isso exigirá configuração. ou seja, porcentagem de imposto sobre vendas por estado, mas também código condicional LegalMethodOfCalculatingWorkingHoursA vs B

Se o seu aplicativo estiver hospedado / on-line, você poderá adotar uma abordagem de microsserviços ao código condicional, mas uma solução off-line terá que agrupar todos os módulos opcionais e selecionar entre eles

Você encontrará alguns módulos reutilizados em todos os estados, como impostos sobre vendas e outros legais, usados ​​apenas em um único estado. Você também descobrirá que as leis mudam com o tempo. portanto, os módulos utilizados variam de acordo com o tempo em um único estado

Então, eu iria nomear por funcionalidade e não por estado.

Ewan
fonte
Eu gosto disso - ramificações de código com base na funcionalidade, por exemplo, "deve perguntar ao endereço" "a entrega é isenta de impostos". Em seguida, a configuração para que mapeia cada estado para um conjunto de funcionalidades.
paj28