Outra maneira de perguntar isso é; por que os programas tendem a ser monolíticos?
Estou pensando em algo como um pacote de animação como o Maya, que as pessoas usam para vários fluxos de trabalho diferentes.
Se os recursos de animação e modelagem fossem divididos em seu próprio aplicativo separado e desenvolvidos separadamente, com arquivos sendo passados entre eles, eles não seriam mais fáceis de manter?
If the animation and modelling capabilities were split into their own separate application and developed separately, with files being passed between them, would they not be easier to maintain?
Não misture mais fácil estender com mais fácil manter um módulo - por si - não está livre de complicações ou desenhos dúbios. O Maya pode ser o inferno na terra para manter enquanto seus plugins não o são. Ou vice-versa.Respostas:
Sim. Geralmente, duas aplicações menores e menos complexas são muito mais fáceis de manter do que uma única grande.
No entanto, você recebe um novo tipo de bug quando todos os aplicativos trabalham juntos para atingir uma meta. Para que eles trabalhem juntos, eles precisam trocar mensagens e essa orquestração pode dar errado de várias maneiras, mesmo que todos os aplicativos funcionem perfeitamente. Ter um milhão de aplicativos minúsculos tem seus próprios problemas especiais.
Um aplicativo monolítico é realmente a opção padrão que você cria quando adiciona mais e mais recursos a um único aplicativo. É a abordagem mais fácil quando você considera cada recurso por conta própria. Só depois que cresce, você pode olhar para o todo e dizer "sabe o que, isso funcionaria melhor se separássemos X e Y".
fonte
As coisas raramente são tão simples na realidade.
Dividir definitivamente não ajuda a evitar esses erros em primeiro lugar. Às vezes, pode ajudar a encontrar erros mais rapidamente. Um aplicativo que consiste em componentes pequenos e isolados pode permitir testes mais individuais (tipo de "unidade" -) para esses componentes, o que às vezes facilita a identificação da causa raiz de certos bugs e, portanto, corrige-os mais rapidamente.
Contudo,
mesmo um aplicativo que parece ser monolítico do lado de fora pode consistir em muitos componentes testáveis por unidade, portanto, o teste de unidade não é necessariamente mais difícil para um aplicativo monolítico
como Ewan já mencionou, a interação de vários componentes introduz riscos e erros adicionais. Depurar um sistema de aplicativos com comunicação complexa entre processos pode ser significativamente mais difícil do que depurar um aplicativo de processo único
Isso depende também de quão bem um aplicativo maior pode se dividir em componentes, e quão amplas são as interfaces entre os componentes e como essas interfaces são usadas.
Em resumo, isso geralmente é uma troca, e nada onde uma resposta "sim" ou "não" esteja correta em geral.
Eles? Olhe ao seu redor, existem milhões de aplicativos da Web no mundo que não me parecem muito monolíticos, pelo contrário. Também existem muitos programas disponíveis que fornecem um modelo de plug-in (o AFAIK até o software Maya que você mencionou).
A "manutenção mais fácil" geralmente vem do fato de que diferentes partes de um aplicativo podem ser desenvolvidas mais facilmente por equipes diferentes, para uma carga de trabalho melhor distribuída, equipes especializadas com foco mais claro e assim por diante.
fonte
Vou ter que discordar da maioria neste caso. Dividir um aplicativo em dois separados não facilita o código ou a manutenção de código.
Separar o código em dois executáveis apenas altera a estrutura física do código, mas não é isso que é importante. O que decide o quão complexa é uma aplicação é o quão fortemente acopladas são as diferentes partes que a compõem. Esta não é uma propriedade física, mas lógica .
Você pode ter um aplicativo monolítico que tenha uma clara separação de diferentes preocupações e interfaces simples. Você pode ter uma arquitetura de microsserviço que se baseia nos detalhes de implementação de outros microsserviços e está fortemente associada a todos os outros.
O que é verdade é que o processo de como dividir um aplicativo grande em aplicativos menores é muito útil ao tentar estabelecer interfaces e requisitos claros para cada parte. No DDD, fale que seria criar seus contextos limitados. Mas se você cria muitos aplicativos minúsculos ou um grande que possui a mesma estrutura lógica é mais uma decisão técnica.
fonte
Mais fácil de manter depois de terminar de dividi-los, sim. Mas dividi-los nem sempre é fácil. Tentar dividir um pedaço de um programa em uma biblioteca reutilizável revela onde os desenvolvedores originais não conseguiram pensar onde deveriam estar as costuras . Se uma parte do aplicativo estiver atingindo outra parte do aplicativo, pode ser difícil corrigi-lo. Rasgar as costuras obriga a definir as APIs internas de forma mais clara, e é isso que facilita a manutenção da base de códigos. Reutilização e manutenção são produtos de costuras bem definidas.
fonte
É importante lembrar que correlação não é causalidade.
Construir um monólito grande e depois dividi-lo em várias partes pequenas pode ou não levar a um bom design. ( Pode melhorar o design, mas não é garantido.)
Mas um bom design geralmente leva à construção de um sistema como várias pequenas partes, em vez de um grande monólito. (Um monólito pode ser o melhor design, é muito menos provável que seja.)
Por que as peças pequenas são melhores? Porque eles são mais fáceis de raciocinar. E se for fácil argumentar sobre a correção, é mais provável que você obtenha um resultado correto.
Para citar o CAR Hoare:
Se for esse o caso, por que alguém criaria uma solução desnecessariamente complicada ou monolítica? Hoare fornece a resposta na próxima frase:
E mais tarde na mesma fonte (a Palestra do Prêmio Turing de 1980):
fonte
Esta não é uma pergunta com resposta sim ou não. A questão não é apenas a facilidade de manutenção, mas também o uso eficiente de habilidades.
Geralmente, um aplicativo monolítico bem escrito é eficiente. A comunicação entre processos e entre dispositivos não é barata. Quebrar um único processo diminui a eficiência. No entanto, a execução de tudo em um único processador pode sobrecarregar o processador e diminuir o desempenho. Esse é o problema básico de escalabilidade. Quando a rede entra em cena, o problema fica mais complicado.
Um aplicativo monolítico bem escrito que pode operar eficientemente como um único processo em um único servidor pode ser fácil de manter e manter livre de defeitos, mas ainda assim não é um uso eficiente das habilidades de codificação e arquitetura. A primeira etapa é dividir o processo em bibliotecas que ainda são executadas como o mesmo processo, mas são codificadas independentemente, seguindo disciplinas de coesão e acoplamento flexível. Um bom trabalho nesse nível melhora a capacidade de manutenção e raramente afeta o desempenho.
O próximo estágio é dividir o monólito em processos separados. Isso é mais difícil porque você entra em território complicado. É fácil introduzir erros de condição de corrida. A sobrecarga de comunicação aumenta e você deve ter cuidado com "interfaces de conversação". As recompensas são ótimas porque você rompe uma barreira de escalabilidade, mas o potencial de defeitos também aumenta. Os aplicativos com vários processos são mais fáceis de manter no nível do módulo, mas o sistema geral é mais complicado e difícil de solucionar. As correções podem ser diabolicamente complicadas.
Quando os processos são distribuídos para servidores separados ou para uma implementação no estilo de nuvem, os problemas ficam mais difíceis e as recompensas maiores. A escalabilidade aumenta. (Se você está considerando uma implementação em nuvem que não gera escalabilidade, pense bem.) Mas os problemas que entram nesse estágio podem ser incrivelmente difíceis de identificar e pensar.
fonte
Não . isso não facilita a manutenção. Se alguma coisa bem-vinda a mais problemas.
Por quê?
Agora você tem dois produtos que precisam:
Agora você tem três mercados de consumo: modeladores, animadores e modeladores de animadores
Dito isto, bases de código menores são igualmente fáceis de manter no nível do aplicativo, você simplesmente não vai receber um almoço grátis. Esse é o mesmo problema no coração do Micro-Service / Any-Modular-Architecture. Não é uma panacéia, a dificuldade de manutenção no nível do aplicativo é trocada por dificuldades de manutenção no nível da orquestração. Esses problemas ainda são problemas, eles simplesmente não estão mais na base de código, precisam ser evitados ou resolvidos.
Se a solução do problema no nível de orquestração é mais simples, resolva-o em cada nível de aplicativo, faz sentido dividi-lo em duas bases de código e lidar com os problemas de orquestração.
Caso contrário, não, apenas não faça isso, você seria melhor atendido ao melhorar a modularidade interna do próprio aplicativo. Envie seções do código para bibliotecas coesas e fáceis de manter, nas quais o aplicativo atua como um plug-in. Afinal, um monólito é apenas a camada de orquestração de uma paisagem de biblioteca.
fonte
Havia muitas respostas boas, mas como há quase uma cisão, eu também jogarei meu chapéu no ringue.
Na minha experiência como engenheiro de software, achei que esse não era um problema simples. Realmente depende do tamanho , escala e finalidade do aplicativo. As aplicações mais antigas em virtude da inércia necessária para alterá-las são geralmente monolíticas, pois essa era uma prática comum por muito tempo (o Maya se qualificaria nessa categoria). Suponho que você esteja falando sobre aplicativos mais recentes em geral.
Em aplicações pequenas o suficiente, que são mais ou menos uma preocupação, a sobrecarga necessária para manter muitas partes separadas geralmente excede a utilidade de ter a separação. Se puder ser mantido por uma pessoa, provavelmente poderá ser monolítico sem causar muitos problemas. A exceção a essa regra é quando você tem muitas partes diferentes (um front-end, back-end, talvez algumas camadas de dados no meio) que são convenientemente separadas (logicamente).
Em aplicações muito grandes, mesmo com uma única preocupação, dividi-lo faz sentido na minha experiência. Você tem o benefício de reduzir um subconjunto da classe de erros possível em troca de outros erros (às vezes mais fáceis de resolver). Em geral, você também pode ter equipes de pessoas trabalhando isoladamente, o que melhora a produtividade. Atualmente, muitas aplicações são divididas de maneira bastante fina, às vezes em seu próprio prejuízo. Também participei de equipes nas quais o aplicativo foi dividido em tantos microsserviços desnecessariamente que introduziu muita sobrecarga quando as coisas pararam de se falar. Além disso, ter todo o conhecimento de como cada parte se comunica com as outras partes fica muito mais difícil a cada divisão sucessiva. Existe um equilíbrio e, como você pode ver pelas respostas aqui, a maneira de fazer isso não é muito clara,
fonte
Para aplicativos de interface do usuário, é improvável que diminua a quantidade geral de bugs, mas mudará o equilíbrio da mistura de bugs em direção a problemas causados pela comunicação.
Por falar em aplicativos / sites de interface do usuário - os usuários são extremamente pacientes e exigem baixo tempo de resposta. Isso transforma qualquer atraso na comunicação em bugs. Como resultado, será negociado um potencial decréscimo de bugs devido à menor complexidade de um único componente, com bugs muito rígidos e requisitos de tempo de comunicação entre processos / máquinas.
Se as unidades de dados com as quais o programa lida são grandes (ou seja, imagens), qualquer atraso no processo seria mais longo e mais difícil de eliminar - algo como "aplicar transformação à imagem de 10 mb" ganhará instantaneamente + 20 mb de E / S de disco / rede, além conversão para 2 do formato na memória para o formato serializabe e vice-versa. Realmente, não há muito que você possa fazer para ocultar o tempo necessário ao usuário.
Além disso, qualquer comunicação e, especialmente, E / S de disco, está sujeita a verificações de antivírus / firewall - isso inevitavelmente adiciona outra camada de bugs difíceis de reproduzir e ainda mais atrasos.
"Programa" monolítico dividido brilha onde os atrasos na comunicação não são críticos ou já são inevitáveis
Observe que isso se aplica aos aplicativos de desktop e aos sites - parte do programa voltada para o usuário tende a ser "monolítica" - todo o código de interação do usuário vinculado a um único dado é geralmente executado em um único processo (não é incomum dividir processos por peça de dados, como uma página HTML ou uma imagem, mas é ortogonal a esta pergunta). Mesmo para o site mais básico com entrada do usuário, você verá a lógica de validação sendo executada no lado do cliente, mesmo que torná-lo no servidor seja mais modular e reduza a complexidade / duplicação de código.
fonte
Evita? Bem, não, na verdade não.
Ou seja, todos os erros que você nem sabia que tinha, que você só descobriu quando tentou dividir toda essa bagunça em partes menores. Então, de certa forma, impediu que esses erros aparecessem na produção - mas os erros já estavam lá.
Erros em aplicativos monolíticos têm o potencial de derrubar todo o sistema e impedir que o usuário interaja com seu aplicativo. Se você dividir esse aplicativo em componentes, a maioria dos bugs, por design, afetará apenas um dos componentes.
Se você deseja manter a experiência do usuário a mesma, precisará incluir uma nova lógica para todos esses componentes se comunicarem (por meio de serviços REST, por chamadas do sistema OS, o que você tem) para que eles possam interagir perfeitamente a partir do ponto de vista do usuário.
Como um exemplo simples: seu aplicativo monolítico permite que os usuários criem um modelo e o animem sem sair do aplicativo. Você divide o aplicativo em dois componentes: modelagem e animação. Agora, seus usuários precisam exportar o modelo do aplicativo de modelagem para um arquivo, encontrar o arquivo e abri-lo com o aplicativo de animação ... Vamos ser sinceros, alguns usuários não vão gostar disso, então você deve incluir uma nova lógica para o arquivo. aplicativo de modelagem para exportar o arquivo einicie automaticamente o aplicativo de animação e abra o arquivo. E essa nova lógica, por mais simples que seja, pode ter vários bugs relacionados à serialização de dados, acesso a arquivos e permissões, usuários alterando o caminho de instalação dos aplicativos, etc.
Quando você decide dividir um aplicativo monolítico em componentes menores, espero que você o faça com muito mais conhecimento e experiência sobre o sistema do que quando ele foi projetado pela primeira vez e, graças a isso, você pode aplicar vários refatores para criar o código mais limpo, mais simples, mais eficiente, mais resiliente, mais seguro. E essa refatoração pode, de certa forma, ajudar a evitar bugs. Obviamente, você também pode aplicar a mesma refatoração ao aplicativo monolítico para evitar os mesmos erros, mas não o faz porque é tão monolítico que tem medo de tocar em algo na interface do usuário e quebrar a lógica de negócios ¯ \ _ (ツ) _ / ¯
Portanto, eu não diria que você está impedindo bugs apenas dividindo um aplicativo monolítico em componentes menores, mas você está realmente facilitando chegar a um ponto em que os bugs podem ser mais facilmente evitados.
fonte