Eu trabalho para uma empresa de consultoria há algum tempo, com clientes de vários tamanhos, e vi aplicativos da Web variando em complexidade, desde muito simples:
- MVC
- Camada de serviço
- EF
- DB
Para realmente complexo:
- MVC
- UoW
- DI / IoC
- Repositório
- Serviço
- Testes de interface do usuário
- Testes unitários
- Testes de integração
Mas nos dois extremos do espectro, os requisitos de qualidade são os mesmos. Em projetos simples, os novos desenvolvedores / consultores podem entrar, fazer alterações e contribuir imediatamente, sem precisar percorrer 6 camadas de abstração para entender o que está acontecendo, ou correr o risco de não entender uma abstração complexa e custar mais caro.
Em todos os casos, nunca houve a necessidade de tornar o código permutável ou reutilizável - e os testes nunca foram realmente mantidos após a primeira iteração porque os requisitos foram alterados, consumindo muito tempo, prazos, pressão comercial, etc.
Então, se - no final -
- testes e interfaces não são usados
- desenvolvimento rápido (leia-se: economia de custos) é uma prioridade
- os requisitos do projeto mudarão bastante durante o desenvolvimento
... seria errado recomendar uma arquitetura super simples, mesmo para resolver um problema complexo, para um cliente corporativo? É a complexidade que define soluções corporativas ou é a confiabilidade, # usuários simultâneos, facilidade de manutenção ou todas as opções acima?
Sei que essa é uma pergunta muito vaga, e qualquer resposta não se aplicaria a todos os casos, mas estou interessado em ouvir de desenvolvedores / consultores que estão no ramo há um tempo e que trabalharam com esses graus variados de complexidade , para saber se as abstrações legais, mas caras, valem o custo total, pelo menos enquanto o projeto estiver em desenvolvimento.
Respostas:
Depende do cliente. Muitos ficarão bem com uma abordagem mais direta. Alguns pensam que você é incompetente porque essa abordagem simples não resolve seus problemas - a coisa toda "essa coisa deve ser super barata por uma razão ..." que faz com que algumas coisas sejam muito mais caras do que custam.
Eu diria que não há nenhuma maneira no inferno de que você possa criar um software não trivial de maneira econômica sem um desses. Como empresa, se você tentasse me vender algo sem eles, eu temeria que você me envolvesse com uma pilha completamente inflexível e inatingível de cocô de cachorro fumegante. ( edite: para ficar claro, eu estou falando de interfaces aqui, não
interfaces
. Programas funcionais e de procedimentos não são todos um monte de porcaria, apesar de não terem interfaces no estilo Java.)Como projetistas de programas, precisamos fazer palpites sobre onde as coisas vão mudar e desenhar linhas lá para que as coisas que mudam possam fazê-lo de maneira rápida, fácil e correta. Boas abstrações economizarão dinheiro com o tempo, porque mudanças inevitáveis se tornam baratas.
Mas não se engane, o termo "astronauta da arquitetura" existe por uma razão. Você nem sempre está construindo o ônibus espacial. Adicionar abstrações ruins que existem no meio das coisas que precisam ser alteradas ou existem para suportar mudanças que não existem ... elas podem custar.
Mas, na minha experiência, eu ouvi as pessoas queixam-se sobre o código abstraído, mas eu só vi projetos falham devido ao código de sub-abstraída.
fonte
Arquiteto, ou não arquiteto
Para reformular Einstein, "as coisas devem ser o mais simples possível - mas não mais simples". É importante entender o verdadeiro uso de algumas arquiteturas - e elas não são necessariamente para o desempenho individual, nem para a satisfação no trabalho.
Às vezes, as arquiteturas são tão complicadas porque um projeto corporativo é tão grande, com tantas pessoas trabalhando, que a arquitetura é amplamente para permitir que tantas pessoas trabalhem em direção a algo sem que todos tropeçam em todos os outros. Às vezes, são pouco mais que a complexidade adicionada que reduz a produtividade individual e dificulta o trabalho - mas permite que um grande número de pessoas trabalhe. Isso funciona quando o esforço adicional supera a vontade de viver diminuída individualmente, quero dizer "produtividade".
Esta é a situação do seu cliente? Bem, se o orçamento deles não estiver na casa dos milhões para este projeto, talvez não. Se estiver abaixo de 100k, quase certamente não. Você constrói um bunker de concreto para um reator nuclear, não um fogão a lenha :)
Não é necessariamente errado sugerir "a coisa mais simples que poderia funcionar" para o seu cliente, se é isso que a situação exige. Pode ser a melhor maneira possível de lidar com isso. A maneira mais fácil de ver é compará-la a projetos comercialmente disponíveis / de código aberto projetados para realizar uma tarefa semelhante (essa é sua pesquisa de mercado de due diligence, enfim) e ver o que eles levaram para fazer o que fizeram.
Obviamente, quando você trabalha com milhões de dólares, deve estar ciente de alguns incentivos perversos em jogo. Em suma, "cobertura do burro": se você recomenda um sistema de arquitetura super complexo que exige que o doutorado entenda corretamente, quando vai para o inferno, quem foi a culpa? Não é claro que você é sua - você sugeriu apenas o melhor em tecnologias sofisticadas que todo mundo diz ser o melhor - mas elas são "complicadas" e "difíceis", então a culpa é das pessoas que tentaram implementá-lo. Eles não devem ter sido suficientemente espertos ou habilidosos o suficiente ... em outras palavras, muitos conselhos são dados para garantir que você não fique mal quando os projetos falham, o que inevitavelmente deve, pois nem todos os projetos são bem-sucedidos. É ruim, mas é um fato da nossa realidade.
Falha em seguir adiante
Eu sugeriria que a falha em atualizar continuamente os testes e acompanhar as decisões de arquitetura (lançar planos quando eles são alterados em vez de atualizá-los etc.) é o motivo pelo qual muitos sistemas acabam sendo descartados e reescritos do zero ou substituídos por atacado por um novo ' solução 'alguns anos no caminho.
Quando coisas que impõem clareza e consistência são jogadas fora por conveniência, às vezes é fácil pensar que você era muito astuto e realmente está "Fazendo as Coisas" quando, na verdade, você fez mudanças futuras mais difíceis e mais complicadas; é muito comum roubar a produtividade futura para obter ganhos imediatos. É ruim especificamente quando ninguém percebe que é o que está acontecendo.
Os testes, por exemplo, são especificamente mais adequados para quando as coisas mudam. Você muda os testes para refletir qual é a nova direção e depois conserta todas as coisas que agora estão "quebradas" porque as pessoas mudaram de idéia ou perceberam que haviam perdido algo da última vez. É como desistir de dormir porque você tem muito o que fazer esta semana - isso vai dificultar as coisas.
Em conclusão, "depende" (útil, não é?)
A complexidade arquitetônica é um custo indireto, como alugar um espaço maior para um negócio de tijolo e argamassa; isso só faz sentido quando há uma complexidade real que precisa ser gerenciada. Se uma equipe de três estiver trabalhando em uma solução relativamente convencional, MVC simples e ferramentas mínimas provavelmente serão suficientes.
Se é uma solução de software empresarial complexa, com vários subsistemas, com milhões no orçamento e pelo menos meia dúzia de equipes de 3 a 5 anos? Você estará implorando pelo amor doce e doce que somente a engenharia de ida e volta na análise de programas orientada a objetos e todos os seus gráficos, diagramas e modelos podem dar. Qualquer coisa para ajudá-lo a manter as dezenas ou centenas de pares de olhos olhando sem piscar para você, imaginando o que eles devem fazer hoje e como devem fazer qualquer coisa.
fonte
Bem-vindo à consultoria.
Um ótimo lugar para ganhar muito dinheiro entregando recursos rapidamente aos clientes.
Se você procura criar um software bonito, sustentável e adaptável que funcione bem agora e no futuro, recomendo que você trabalhe em um setor específico, como saúde ou governo, onde possa criar um nicho melhor para um trabalho de qualidade.
fonte
O que você ganha com um design sólido é um ciclo de mudança mais confiável a longo prazo. O custo é inicialmente mais alto porque você precisa de programadores treinados adequadamente e de um design adequado; no entanto, a intenção é manter o custo de alterações posteriores de disparos fora de controle.
Sem uma arquitetura sólida, as mudanças são apenas mais baratas no começo. À medida que o projeto evolui, as mudanças se tornam cada vez mais caras. Isso, combinado com o desejo de mão-de-obra mais barata e iteração mais rápida, pode acabar com o projeto, pois as mudanças acabarão custando mais do que a empresa está disposta a pagar e levar mais tempo do que a empresa pode esperar. Mudanças posteriores que poderiam levar uma equipe média e um tempo médio exigirão uma equipe sobre-humana e um longo tempo para examinar os anos de código e refatorar o suficiente para fazer alterações com segurança.
Se o cliente entender e quiser fazer esse sacrifício, faça as alterações necessárias por qualquer método mais rápido. Mas não é prudente (e possivelmente desonesto) fazer essas compensações por eles, pois esse processo afetará suas decisões de negócios.
Parte do trabalho é entender todas as abstrações listadas, não apenas perguntar "Isso é necessário?" mas para entender quando e por que eles são necessários e descobrir como aplicar esses padrões como parte do trabalho com o software.
Outra parte do trabalho é entender que os clientes geralmente julgam o trabalho pelo que podem ver (a interface do usuário, a funcionalidade) e devem ser instruídos sobre o que não podem ver (o estado da base de código).
fonte
Complicado é relativo. Quando eu comecei a aprender a programar, o conceito de ponteiros, especialmente as listas vinculadas, era complicado ("Como você pode ter algo que tem a si próprio como um campo")?
Quando comecei a aprender programação funcional, o conceito de lambda parecia complexo. Mas então eu o relacionei com a idéia de um ponteiro de função do C ++ e era simples. E assim por diante, com curry, e conclusões, e assim por diante.
Quando comecei a aprender TDD, pensei que era complexo ou que acrescentava uma sobrecarga ao processo de desenvolvimento. Agora, não sinto que meu código esteja completo, a menos que eu tenha testes pelo menos cobrindo o caminho feliz. A injeção de dependência e o uso de interfaces, em vez de classes concretas, parecem complexos a princípio. Mas eles permitem que você construa seu código com a suposição de que você elaborará os detalhes das dependências e se concentrará primeiro nas construções de nível superior.
Confira o código limpo e o codificador limpo de "tio Bob" Martin. A primeira fala sobre como codificar melhor. O segundo fala sobre como ser um codificador melhor. Há uma diferença entre os dois.
Para fazer uma analogia, estou aprendendo violão. Estou na fase em que posso tocar melodias e acordes simples. A transição entre acordes e posições é difícil. Ao praticar mais, poderei atingir essas transições mais facilmente e isso se tornará uma segunda natureza para mim.
Uso o padrão de repositório / unidade de trabalho para poder usar um repositório na memória enquanto construo a funcionalidade básica e converter em um repositório "sql lite" ou "odata" à medida que me aproximo da entrega. Observe que isso me permite concluir mais funcionalidades antes mesmo de a infraestrutura final estar instalada (ou mesmo decidida). As abstrações permitem criar zombarias e stubs mais facilmente, para que eu possa verificar se o código que depende das abstrações funciona conforme o esperado. Mais uma vez, posso concluir os recursos de cima para baixo.
Eu diria que é errado criar a infraestrutura primeiro. O simples fato é que é anti-ágil. Se eu gasto um sprint em "infraestrutura", estou construindo coisas que nem tenho certeza de que precisarei no final e que os usuários não terão nada para olhar para fornecer feedback.
É isso que as abstrações fornecem. Quanto mais você pratica o uso deles, mais eles se tornam uma segunda natureza, e você analisará essa discussão e se maravilhará com o quanto desenvolveu. Assim como espero, em poucos anos me perguntarei como as transições de acordes foram um desafio para mim.
fonte
Não concordo plenamente com sua afirmação de que a abstração aumenta automaticamente a complexidade. A abstração é a principal razão pela qual hoje em dia não é necessário resolver o código da máquina.
O problema às vezes com abstrações é que elas tendem a se concentrar no funcionamento interno, em vez de esconder a complexidade para seus usuários finais. As abstrações devem isolar a lógica e promover a reutilização. Além disso, acho que o teste é uma ótima maneira de desafiar o projeto arquitetônico. Principalmente porque obriga a olhar para o seu código do ponto de vista do usuário.
Os problemas que você mencionou sobre falta de tempo são a principal causa do mau design. Um bom design geralmente não vem instantaneamente, mas através de iterações e refinamentos. Como geralmente extraímos requisitos de nossos clientes é por meio de histórias de usuários. Dessa forma, o cliente pode pensar sobre o que e como ele deseja usar o sistema. Além disso, se o arquiteto está ciente das intenções do sistema, decisões de projeto ou técnicas de abstração apropriadas podem ser escolhidas para adicionar flexibilidade ao sistema. Não porque eles são legais ou agradáveis.
fonte
Respondendo às suas perguntas ...
Absolutamente não.
Na perspectiva do cliente
Como afirmado acima, depende em grande parte do cliente. Também depende da sua capacidade de avaliar com precisão quais soluções são adequadas para o seu cliente. Embora sempre haja um custo percebido para o valor desejado, como consultor, é seu trabalho definir as expectativas apropriadas do cliente. Em alguns casos, você terá que atender a essa percepção. Em outros, será do seu interesse corrigi-los. Afinal, você deve ser o especialista para o seu cliente. E se não estiver, você deve ter o conhecimento necessário para se tornar esse especialista. É para isso que eles pagam.
Da perspectiva do desenvolvedor
A parte mais difícil de escolher qual arquitetura usar é, muitas vezes, estimar corretamente a quantidade de trabalho necessária para utilizar a tecnologia para atender às necessidades específicas. Isso pode levar muito rapidamente a projetos que não atendem às expectativas do cliente. Entenda que alguns projetos são realmente feitos mais rapidamente usando esses trechos de código "complexos" mencionados. Também se entende que alguns não são. Você deve fornecer essa medida, com base no que você ou sua equipe sabem.
Embora as especificidades possam variar, em geral, uma solução corporativa é uma solução de software que se aplica a uma ampla audiência combinada. O número de usuários simultâneos pode ou não ser um fator, embora geralmente seja. O número total de usuários, freqüentemente em uma variedade de funções comerciais, é um dos maiores fatores determinantes para determinar se a solução é "corporativa".
Muitas soluções empresariais são altamente complexas, mas algumas são bastante simples. Embora a empresa ofereça um ar de confiabilidade (e certamente deva ser mantido em um determinado padrão), diferentes soluções têm diferentes níveis de confiabilidade.
Facilidade de manutenção é algo que eu acho que todo desenvolvedor (independente ou membro da equipe) se esforça, não é necessariamente tão fácil de conseguir. O importante é que exista um procedimento de manutenção que tenha diretrizes firmes, em vez de ser "fácil". Lembre-se de que diferentes bases de código terão níveis de facilidade substancialmente diferentes, dependendo das filosofias, metodologias, atividade do ambiente (comercial) e complexidade do código.
Reagindo às suas outras declarações ...
Muitas vezes, nunca há uma necessidade específica de fazê-lo. Este deve ser seu objetivo, em todos os momentos, no entanto. Considere isto ... Você pode ter um cliente que exija a capacidade de acessar ou exibir seu calendário na página da web. Se você tornar seu próprio código reutilizável, quando outro cliente solicitar a mesma coisa, você já executará parte do trabalho. Se não o fizer, terá que fazer tudo de novo. Todo problema de cliente é geralmente um problema que outro cliente no futuro pode precisar. Em outras palavras, todo cliente com quem você trabalha deve ter o potencial de reduzir o custo do trabalho para seus futuros clientes (não necessariamente o custo do produto).
Eu argumentaria aqui que a metodologia de teste não foi suficientemente abstraída. Recentemente, usei um código que fazia seus próprios testes de unidade diretamente dentro de si. Um costume
assert
e umaexpect
função foram feitos para acomodar as necessidades do projeto. Sempre que fosse necessário um teste de unidade, ele poderia ser aplicado sem mesmo ajustar o código. De fato, o código é distribuído ativamente com as declarações e espera ainda estar lá. Ele fez essas verificações como parte do código de trabalho.Muitas vezes, descobri que a pressão extra dos negócios e os prazos que impedem o processo de codificação foram culpa do desenvolvedor, não do cliente. Embora nem sempre seja esse o caso, muitas vezes a pressão nos negócios é causada pela percepção de falha em atender às expectativas do cliente. Quando os prazos impedem o código, geralmente é porque o desenvolvedor falhou ao avaliar com precisão a quantidade de trabalho necessária para o código funcional utilizável. Em outras palavras, programe-os (os clientes esperam) , meça-os (futuros clientes esperam) , execute-os (os usuários exigem) e seja pago por eles (seu contrato deve exigir) .
fonte
Muito do que essa pergunta é incrivelmente subjetivo, acho importante trazer alguns dados sobre os custos compostos da complexidade da arquitetura. Existe um estudo de caso realmente interessante vindo do MIT Sloan que mede
Basicamente, eu diria que existe um meio feliz em que cada base de código deve se esforçar para encontrar entre (A) a simplicidade para que a produtividade do desenvolvedor seja alta e (B) a previsão para que a funcionalidade não seja comprometida quando novos recursos forem adicionados.
O estudo de caso foi realizado nessa empresa com uma base de código monolítica que possuía um núcleo de alta complexidade (pense em utilitários e coisas de alta abstração) e periferia de menor complexidade (pense em recursos mais recentes com poucas dependências). Entre a periferia e o núcleo, a produtividade do desenvolvedor diminuiu 50% (coisas malucas) e os defeitos aumentaram 2,6x.
fonte
Posso me relacionar com suas dúvidas sobre técnicas complexas de desenvolvimento de software e acho que existem muitas pessoas que podem, exatamente pelas razões que você nomeou: Elas acrescentam uma sobrecarga à criação inicial de um novo sistema, mas nem sempre mostram instantaneamente seus benefícios.
Claramente, isso não significa que eles não existem, pois para cada conceito existe uma razão, na maioria das vezes boa. No total, eles devem reduzir o trabalho necessário para finalizar um projeto e aprimorá-lo posteriormente.
Em teoria, é claro, e aposto que você aprendeu todos esses benefícios teóricos e agora, mais do que nunca, os vê falhar. E isso também pode ter uma boa razão, usar um conceito correto não é tão fácil quanto entender por que ele é usado e, embora você tenha a experiência necessária para decidir quando abstrair e quando não, seus clientes ainda não o fizeram.
Usar um conceito em todos os pontos possíveis do seu projeto pode custar muito tempo (consulte a Telatsyns responder por uma frase simples e clara) e até mesmo usar um conceito no lugar certo pode custar, se você não tiver experiência suficiente usando . Como você disse, esses não são conceitos simples, mas, às vezes, conceitos realmente complexos que precisam ser ajustados à sua situação, uma compreensão teórica pode não ser suficiente para usá-la de maneira rápida e correta.
E por esses motivos, não é de surpreender que seus clientes, sem realmente perceberem, se afastem dos conceitos, abandonem seus testes e abstrações e voltem a trabalhar de novo com simplicidade.
Em relação à grande barreira que pode ser a engenharia de software, sugiro este artigo: As sete etapas da especialização em engenharia de software Eu me deparei com ela em algum lugar desta página e ela expressa pensamentos e experiências realmente interessantes.
fonte
Eu diria que, se você estiver desenvolvendo aplicativos para a empresa, você ou alguém encarregado de seus projetos (gerente de projetos) deve ter uma ideia melhor da quantidade de trabalho que deve ser direcionado aos projetos. Se estiver perdendo tempo, discuta sua opinião com o gerente de projeto. A maneira como me sinto e opero é sempre de acordo com o tipo de julgamento, mas sempre procuro aquele cliente que lhe dará uma bola curva. Eu erro ao fazer um bom trabalho pontilhando seus 's' e cruzando seus 's'. Eu também me certificaria de ter o gerenciamento adequado do ciclo de vida do aplicativo, para que a maior parte da sobrecarga seja automatizada, de modo a poupar tempo, etc ... Espero que ajude!
fonte