Eu gosto do SOLID e tento o meu melhor para usá-lo e aplicá-lo no desenvolvimento. Mas não posso deixar de sentir que a abordagem do SOLID transforma seu código em código 'framework' - ou seja, código que você criaria se estivesse criando uma estrutura ou biblioteca para outros desenvolvedores usarem.
Geralmente pratiquei 2 modos de programação - criando mais ou menos exatamente o que é solicitado por meio de requisitos e KISS (programação típica), ou criando lógica, serviços muito genéricos e reutilizáveis, etc., que fornecem a flexibilidade que outros desenvolvedores podem precisar (programação de estrutura) .
Se o usuário realmente deseja que um aplicativo faça xey, faz sentido seguir o SOLID e adicionar um monte de pontos de entrada de abstração, quando você nem sabe se esse é um problema válido para começar com? Se você adicionar esses pontos de entrada da abstração, está realmente cumprindo os requisitos do usuário ou está criando uma estrutura em cima da estrutura existente e da pilha de tecnologias para facilitar futuras adições? Nesse caso, você está atendendo aos interesses do cliente ou do desenvolvedor?
Isso é algo que parece comum no mundo Java Enterprise, onde parece que você está projetando sua própria estrutura em cima do J2EE ou Spring para que seja um UX melhor para o desenvolvedor, em vez de se concentrar no UX para o usuário?
fonte
Respostas:
Sua observação está correta, os princípios do SOLID são IMHO feitos com bibliotecas reutilizáveis ou código de estrutura em mente. Quando você segue todos eles cegamente, sem perguntar se faz sentido ou não, corre o risco de generalizar demais e investir muito mais esforço em seu sistema do que provavelmente o necessário.
Isso é uma troca e precisa de alguma experiência para tomar as decisões corretas sobre quando generalizar e quando não. Uma possível abordagem para isso é seguir o princípio YAGNI - não torne seu código SÓLIDO "apenas por precaução" - ou, para usar suas palavras: não
em vez disso, forneça a flexibilidade que outros desenvolvedores realmente precisam assim que precisam , mas não antes.
Portanto, sempre que você tiver uma função ou classe em seu código, não tem certeza se ela pode ser reutilizada, não a coloque no seu framework agora. Aguarde até ter um caso real de reutilização e refatorar para "SOLID o suficiente para esse caso". Não implemente mais configurabilidade (seguindo o OCP) ou pontos de entrada de abstração (usando o DIP) em uma classe que você realmente precise para o caso real de reutilização. Adicione a próxima flexibilidade quando o próximo requisito de reutilização estiver realmente presente.
Obviamente, essa maneira de trabalhar sempre exigirá uma certa refatoração na base de códigos de trabalho existente. É por isso que os testes automáticos são importantes aqui. Portanto, tornar seu código SÓLIDO o suficiente desde o início para testá-lo por unidade não é uma perda de tempo, e isso não contradiz o YAGNI. Os testes automáticos são um caso válido para "reutilização de código", pois o código em jogo é usado tanto no código de produção quanto nos testes. Mas lembre-se, basta adicionar a flexibilidade que você realmente precisa para fazer os testes funcionarem, nem menos, nem mais.
Esta é realmente a velha sabedoria. Há muito tempo antes que o termo SOLID ficou popular, alguém me disse antes de tentar escrever re código utilizável, devemos escrever utilizável código. E ainda acho que é uma boa recomendação.
fonte
Pela minha experiência, ao escrever um aplicativo, você tem três opções:
No primeiro caso, é comum acabar com um código fortemente acoplado que carece de testes de unidade. Claro que é rápido escrever, mas é difícil de testar. E é uma dor real certa mudar depois quando os requisitos mudarem.
No segundo caso, uma quantidade enorme de tempo é gasta tentando antecipar necessidades futuras. E com muita freqüência esses requisitos futuros previstos nunca se materializam. Este parece o cenário que você está descrevendo. É um desperdício de esforço na maioria das vezes e resulta em código desnecessariamente complexo, que ainda é difícil de mudar quando um requisito que não era esperado para surgir.
O último caso é o único a apontar na minha opinião. Use TDD ou técnicas semelhantes para testar o código à medida que avança e você acabará com um código fracamente acoplado, fácil de modificar e ainda rápido de escrever. E, ao fazer isso, você naturalmente segue muitos dos princípios do SOLID: pequenas classes e funções; interfaces e dependências injetadas. Liskov é geralmente mantida feliz também, pois classes simples, com responsabilidades únicas, raramente desrespeitam seu princípio de substituição.
O único aspecto do SOLID que realmente não se aplica aqui é o princípio de aberto / fechado. Para bibliotecas e estruturas, isso é importante. Para um aplicativo independente, não muito. Realmente é um caso de escrever código que segue " SLID ": fácil de escrever (e ler), fácil de testar e fácil de manter.
fonte
A perspectiva que você tem pode ser distorcida pela experiência pessoal. Essa é uma inclinação escorregadia de fatos individualmente corretos, mas a inferência resultante não é, mesmo que pareça correta à primeira vista.
Isso significa que, quando você interage com estruturas e bibliotecas menores, o código de boas práticas com o qual você interage será mais comumente encontrado nas estruturas maiores.
Essa falácia é muito comum, por exemplo, todos os médicos pelos quais fui tratado eram arrogantes. Portanto, concluo que todos os médicos são arrogantes. Essas falácias sempre sofrem uma inferência geral baseada em experiências pessoais.
No seu caso, é possível que você tenha experimentado predominantemente boas práticas em estruturas maiores e não em bibliotecas menores. Sua observação pessoal não está errada, mas é uma evidência anedótica e não é universalmente aplicável.
Você está confirmando isso aqui. Pense no que é uma estrutura. Não é uma aplicação. É um "modelo" generalizado que outras pessoas podem usar para criar todos os tipos de aplicativos. Logicamente, isso significa que uma estrutura é construída em uma lógica muito mais abstrata para ser útil a todos.
Os construtores de estruturas são incapazes de usar atalhos, porque eles nem sabem quais são os requisitos dos aplicativos subseqüentes. Construir uma estrutura inerentemente os incentiva a tornar seu código utilizável para outras pessoas.
Os construtores de aplicativos, no entanto, têm a capacidade de comprometer a eficiência lógica porque estão focados na entrega de um produto. Seu principal objetivo não é o funcionamento do código, mas a experiência do usuário.
Para uma estrutura, o usuário final é outro desenvolvedor, que estará interagindo com seu código. A qualidade do seu código é importante para o usuário final.
Para um aplicativo, o usuário final é um não desenvolvedor, que não estará interagindo com seu código. A qualidade do seu código não tem importância para eles.
É exatamente por isso que os arquitetos de uma equipe de desenvolvimento costumam atuar como impositores de boas práticas. Eles estão a um passo da entrega do produto, o que significa que tendem a olhar o código objetivamente, em vez de se concentrar na entrega do próprio aplicativo.
Esse é um ponto interessante, e é (na minha experiência) a principal razão pela qual as pessoas ainda tentam justificar evitar boas práticas.
Para resumir os pontos abaixo: Ignorar as boas práticas só pode ser justificada se seus requisitos (como atualmente conhecidos) forem imutáveis e nunca haverá nenhuma alteração / adição à base de código. Alerta de spoiler: Isso raramente é o caso.
Por exemplo, quando escrevo um aplicativo de console de 5 minutos para processar um arquivo específico, não uso boas práticas. Como só vou usar o aplicativo hoje, e ele não precisa ser atualizado no futuro (seria mais fácil escrever um aplicativo diferente caso eu precise de um novamente).
Digamos que você possa criar um aplicativo de má qualidade em 4 semanas e em 6 semanas. À primeira vista, construir de má qualidade parece melhor. O cliente obtém seu aplicativo mais rapidamente e a empresa precisa gastar menos tempo com os salários dos desenvolvedores. Vitória / vitória, certo?
No entanto, esta é uma decisão tomada sem pensar no futuro. Devido à qualidade da base de código, fazer uma grande alteração na versão mal feita levará 2 semanas, enquanto as mesmas alterações na versão adequada levar 1 semana. Pode haver muitas dessas mudanças no futuro.
Além disso, há uma tendência de que as mudanças requeiram inesperadamente mais trabalho do que você pensava inicialmente em bases de código construídas de maneira péssima, provavelmente aumentando o tempo de desenvolvimento para três semanas em vez de duas.
E também há a tendência de perder tempo caçando bugs. Esse é geralmente o caso em projetos nos quais a criação de log foi ignorada devido a restrições de tempo ou a pura relutância em implementá-lo, porque você trabalha distraidamente com a suposição de que o produto final funcionará conforme o esperado.
Nem precisa ser uma grande atualização. No meu atual empregador, vi vários projetos que foram construídos de forma rápida e suja e, quando o menor erro / alteração precisava ser feito devido a uma falta de comunicação nos requisitos, que levou a uma reação em cadeia da necessidade de refatorar módulo após módulo . Alguns desses projetos acabaram em colapso (e deixaram para trás uma bagunça insustentável) antes mesmo de lançar sua primeira versão.
As decisões de atalho (programação rápida e suja) são benéficas apenas se você puder garantir conclusivamente que os requisitos estão exatamente corretos e nunca precisarão ser alterados. Na minha experiência, nunca encontrei um projeto em que isso fosse verdade.
Investir o tempo extra em boas práticas é investir no futuro. Bugs e alterações futuras serão muito mais fáceis quando a base de código existente for baseada em boas práticas. Já estará pagando dividendos após apenas duas ou três alterações.
fonte
Como o SOLID transforma código simples em código de estrutura? Eu não sou um stan para o SOLID de forma alguma, mas não é realmente óbvio o que você quer dizer aqui.
Admito que não penso em termos do SOLID, porque vim através das escolas de programação Gang of Four e Josh Bloch , não da escola Bob Martin. Mas acho que, se você pensa em "SOLID" = "adicionando mais camadas à pilha de tecnologia", está lendo errado.
PS Não venda os benefícios do "melhor UX para o desenvolvedor" a curto prazo. O código passa a maior parte de sua vida em manutenção. Um desenvolvedor é você .
fonte
class A{ int X; int Y; } class A_setX{ f(A a, int N) { a.X = N; }} class A_getX{ int f(A a) { return X; }} class A_setY ... etc.
Acho que você está olhando de um ponto de vista meta demais com sua reivindicação de fábrica. A inicialização não é um aspecto do problema do domínio.