Disclaimer: Os exemplos usados aqui embora baseados em projetos reais são de minha autoria. Eu simplifico/altero alguns detalhes de forma a simpli...
For further actions, you may consider blocking this person and/or reporting abuse
Parabéns pelo artigo e obrigado por compartilhar sua visão e experiência. Poderia endossar praticamente tudo que você mencionou neste artigo.
Eu somente gosto de trazer a tona uma deficiência da comunidade como um todo que diz respeito a conceitos. Estas propostas de arquiteturas de aplicação citadas estão repletas de conceitos, normalmente abordagens para problemas conhecidos.
Muitas delas não lhe dizem como você deve exatamente implementar, apenas mencionam que determinadas preocupações precisam ser tratadas.
Vou citar um exemplo muito simples, apesar de ser mais relevante pra quem usa java creio que qualquer desenvolvedor de outra linguagem vai entender o objetivo.
Imagine que existe uma regra de negócio que o CPF deve estar válido (isso pode ser tratado como regra de formatação ou algo assim, mas tem o famoso mod11 e tal). Uma outra regra para o nome ter entre 3 e 100 caracteres, e outra regra de que a data de nascimento deve estar obrigatoriamente no passado. Como se tratam de regras de domínio de negócio a sugestão é que estas sejam tratadas nas classes de domínio. Pois bem, se usar Beans Validation do java, três anotações em atributos de uma classe de domínio ou DTO resolvem isso. Se no controller vc adicionar uma anotação @valid o framework vai invocar estas regras bem antes de processar o controller ou service/entidades. Ai fica a questão: É válido chamar uma regra de domínio na camada do controller?
Entendo que isso esteja bem alinhado com o que muitos de nós já enfrentamos. Todos querem fazer sistemas à prova de tudo e perdemos tempo e dinheiro protegendo e preparando a aplicação para um cenário que simplesmente não existe. Creio que você foi muito feliz ao não atacar a metodologia mas sim a implementação. Muitos dos princípios que você adotou são usados pelas sugestões de arquitetura, apenas muda a nomenclatura mas os princípios são os mesmos.
Como sempre, o bom senso deve prevalecer e só nos alinharmos a uma arquitetura mais complexa quando precisarmos lidar com problemas e cenários mais complexos.
Tenho um exemplo que gosto de citar sobre um sistema monolitico com um banco H2 que suportou o fluxo de uma transpordora por um mês inteiro depois que uma versão mais moderna não parava de pé por consumir mais recursos e trabalhar distribuida num ambiente com uma infraestrutura de rede instável.
Opa Marcelo, obrigado pelo comentário. Gostei bastante do seu exemplo com o Beans Validation.
Sendo bem honesto, eu talvez sendo o paranóico que eu sou, implementaria a validação no controller (fail-fast) e DE NOVO no domínio (entidades consistentes).
Você está certo, o foco do post foi mais mostrar como eu vi sistemas sendo feitos e demonstrar como isso quebraria outras arquiteturas mas mesmo assim os sistemas funcionam e são bem testados/etc...
A única parte que eu discordo levemente de você é essa aqui:
No caso da Clean especificamente. No livro que descreve a Clean o autor é BEM prescritivo e deixa claro como deve ser implementada. Somos obrigados a segui-lo cegamente? Não. Mas aí a nossa arquitetura é mais uma clean-hugo ou clean-marcelo do que a clean-architecture (e tudo bem ser assim, tá?).
Se curtiu dá uma olhada nos outros posts, seu comentário me agregou bastante. Obrigadão!
Olá Hugo, muito interessante teu artigo principalmente quando relata problemas enfrentados no "mundo real" que estão poucos ligados de fato ao modelo arquitetônico da solução.
Tenho algumas questões e gostaria do teu ponto de vista. Quero ressaltar que são dúvidas embasadas em domínios que possuem regras de negócio e não CRUDs:
Boas perguntas Kauan! Vou considerar o disclaimer que você mencionou (não-cruds). Vamos lá:
Gostei demais das perguntas, torna a discussão bem rica! obrigado demais por participar.
Kauan,
Atualmente para que as entidades sejam gerenciadas através do EntityManager ou Session do Hibernate não é necessário que a classe contenha getters e setters, apenas o construtor default. Então é possível favorece o uso do construtor cheio ou de builders para manter o encapsulamento, e também distribuir a responsabilidades de atualizar o estado dos atributos a metodos. Dessa forma podemos nos beneficiar do mecanismo de Dirty Checking do Hibernate para que ele mesmo defina qual são as melhores operações SQL e o melhor momento para atualizar o estado da entidade no BD.
Excelente conteúdo!
Sou estagiário back-end e já estava ficando maluco tentando entender clean arch :D Fiz uma API simples de quiz usando n-tiers, mas falta muita coisa para implementar e colocar SOLID e padrões de projeto que estou aprendendo em prática nela. Obrigado pela clareada de ideias.
Cara muito legal o seu artigo, bem didático e pratico ao mesmo tempo, ficou bem simples pra que está querendo aprender sobre design de código, já sai sabendo os porquês de muita coisa.
Parabéns pelo belo trabalho!
Muito bom o artigo Hugo, bem escrito e fácil de compreender.
Eu ia comentar minha dúvida, mas os comentários estão tão bons que já não tenho mais dúvidas.
A paz de espírito que tenho em mexer em códigos com mapeamentos 1:1 é indescritível haha, um momento de descanso das abstrações complexas. Eu gosto muito dessa pegada mais simples, mas meu ego idiota fica pensando em melhoria precoce o tempo todo.
Bom artigo. Parabéns pelo material. Agora para mim não ficou claro qual a diferença entre essa arquitetura simples e uma arquitetura limpa! Poderia exemplificar?
A arquitetura limpa prega menos acoplamento com os frameworks e tecnologias específicas. Ela também faz uma inversão na dependência fazendo a camada de persisência depender do domínio e não o contrário como na clássica arquitetura n-tier (renomeada aqui pra arquitetura "simples).
Vê esse artigo aqui que pode ficar mais claro: zup.com.br/blog/clean-architecture...
Se você ainda tiver dúvidas, dá o toque que a gente conversa mais sobre o assunto :)
Certo. Na verdade uso arquitetura limpa no meu dia a dia. Como no caso você não deixou claro a sua relação de dependências com as outras camadas, se são camadas se comunicando com interfaces ou com classes mais concretas fiquei curioso para achar.
Com pequenas nomenclaturas essa arquitetura se tornaria um arquitetura limpa.
Mas obrigado pela resposta.
Mas eu deixo claro a relação de dependência. Você pode ver pelas setas no segundo diagrama de caso de uso ou no diagrama de camadas que existe uma dependencia explícita entre a camada de caso de uso e a persistência, por exemplo.
A outra questão é que a dependência se dá a classe concretas, interfaces apenas quando temos mais de 1 implementação do mesmo contrato.
Para essa arquitetura se tornar limpa teríamos que mudar algumas coisas:
Não é algo difícil de fazer pra ser honesto mas o resultado, embora sutil, é bem diferente.
Em relação ao tratamento de erros, você viu em algum momento da sua experiência a necessidade de "traduzir" as exceções entre as camadas (assim como você comentou com os DTOs)?
No geral, eu evito esse captura/captura de exceções e traduz/traduz entre camadas. Eu gosto de classificar as ações entre retryable e non-retryable e deixa ela estourar até a camada mais alto (controller nesse caso).
Você acabou de me dar a idéia pra um excelente post! Eu já falei bastante sobre isso no passado, vou escrever pra vocês ;)
Parabéns pelo artigo! Excelente conteúdo!
Post muito bom e bem escrito. Parabéns!!!
Muito bom o post, valeu por compartilhar!
tem a versão em inglês desse post?
Nope. 100% original em português. Quem sabe eu traduzo?
Artigo muito bom. Tenho algumas questões.
Espero que tenha gostado. Mto obrigado pelas perguntas e se tiver mais dúvidas manda aí!
Fala Hugo, parabéns pelo post e muito obrigado por compartilhar sua reflexão sobre o assunto.
Tenho passado por experiências parecidas, onde me incomodei um pouco em seguir by-the-book tanto a Arquitetura Limpa quanto a Hexagonal, confesso que gosto mais da Hexagonal, mas você mencionou um ponto bem importante(IMHO) onde o case na Netflix eles usaram para resolver um problema, e isso tem me motivado muito quando estou refletindo sobre algum design, qual problema queremos resolver com aquele design?
Tenho tentado pensar em não usar determinada arquitetura só porque alguém usou sem refletir qual o problema esse alguém resolveu com aquela arquitetura.
Em algumas experiências eu senti que trouxe mais complexidade do que ajudou a resolver problemas.
Hoje em dia penso em algo “passeado” em arquitetura limpa mas adaptado sabe (:
Tipo o exemplo que vc deu das entidades de persistência 1:1 com DTO
Enfim, gostei muito da sua reflexão e pensamento do KISS e YAGNI sempre que estiver optando tento pela Arquitetura Limpa quanto Hexagonal.
Um abraço!