Agora eu vi uma arquitetura bem organizada e fácil de entender! Por isso apoio e faço parte da comunidade Tech Leads Club. Alto nível de conhecimento e trazendo na prática conteúdos que podemos aplicar no nosso dia a dia :)
Muito massa Waldemar, normalmente crio uma camada de entidade e uma camada de model. A camada de entidade é uma representação do meu domínio, sem nada de ORM e fica no core. E na minha camada de persistencia crie minha model. A entrada de meu repo sempre é uma entidade, e no repo faço esse parse.
Que visão sobre o grau de acoplamento entre as camadas, é pensando dessa forma concordo contigo pois quando deixamos de passar coisas indevidas para o CORE do negócio se perde o controle do que estão fazendo ali com essa liberdade do driver externo e sabendo limitar essa camada acaba diminuindo o acoplamento!
waldemar, o repository é um conceito simples mas conforme eu estudo mais complexo fica por ter tantas formas e opniões diferentes sobre. Por exemplo, o uso de repository em ORM Active record (eloquent, lucid do adonis etc...), vejo bastante falar que não faz sentido para esses casos e eu concordo. Outra coisa que me confunde bastante e não consigo chegar em um consenso do melhor é o uso de repository especifico ou repository generalizado. Por exemplo, o uso de repository generalizado normalemnte quebra o ISP do SOLID fazendo com que as classes implementem ou tenham acesso a métodos que elas não deveriam ter, vi formas de "driblar" isso com interface segregation (n curti) e composition (achei melhor), porém o que mais me agrada no momento é definir as interfaces específicas e criar repositórios específicos para cada entidade (to no contexto das entidades de tabela e não DDD) mas não sei se é algo bom de verdade. Outro ponto que vi comentando é que o Repository Pattern "verdadeiro" é o repository do DDD/Clean Arch com o uso das entidades de domínio, que eles possuem lógica e fazem o mapeamento das entidades pras tabelas e que o repository usando apenas com entidades de tabela da ORM (TypeORM por exemplo) na verdade sao apenas uma data access layer e não um repository real... o que você diz sobre isso tudo?
Showww as vezes eu faço o mesmo cara! Na questão do prisma a única diferença é que, eu não tenho uma (classe ou entidade model). - Geralmente, eu crio uma interface repository para um contrato, mesmo por que as vezes preciso fazer alguns testes unitários mocados e não quero bater no banco do prisma, por isso a (interface). 😁😅 -A seguir eu crio uma classe (repository de implementação), lá eu adiciono os métodos do prisma e tudo relacionado ao ORM. - Sigo isso, por que já houve uma situação especifica, que tive trocar todas conexão de banco para drive nativos e dessa maneira mechemos somente na camada de persistência (repository)
Ótimo conteúdo, obrigado por compartilhar. Provavelmente terá comentários falando que é desnecessário toda essa complexidade, e que é melhor acoplar pois tbm "resolve" o problema que a tarefa está pedindo e é mais rápido, MAS provavelmente serão comentários de Devs que trabalham em projetos simples, ou que só criam o projeto e não precisam evoluí-lo, ou que nunca trabalharam em uma aplicação gigante legada para entenderem as dores que justificam essa abordagem apresentada no vídeo.
Valeu Luan, a sim, mas quem estiver em um contexto mais simples tem que usar algo simples e acoplado mesmo, mas os princípios que eu falei aqui nem são muito abstratos na verdade. Eu acho que é um nível bom de abstração para se ter ser adicionar muita complexidade.
@@WaldemarNetoDevLab sim, exato, "me de o problema que eu darei a solução". O ponto é que saber os motivos do porque de algumas estruturas serem mais complexas e do entendimento sobre acoplamento (além do grotesco getters e setters de uma entidade anêmica) é o que destrava a mente do Dev ao propor uma estrutura de projeto, principalmente quando forem começar um novo projeto, pois o jeito CRUD simples é o primeiro contato que todos os Devs tem.
Valdemar, eu vi seu vídeo de implementação do pattern repository com mongoose...se você fizesse um usando o typeorm seria INCRÍVEL! Por esse vídeo seu deu pra pegar muita coisa, mas sua explicação é muita boa e um vídeo com repository + typeorm seria maravilhoso demais.
@@WaldemarNetoDevLab Nuu, massa demais! Muito obrigado! Você é minha maior inspiração na área, acho muito incrível o quão dedicado e estudioso você é e tento trazer isso pra minha vida também mesmo com as complicações, quando crescer quero ser igual vc kkkkkk :)
Nesse caso do repository ai vc importa ele direto, não faz a inversão de dependência, como vc faz seus testes automatizados? Nesse caso o que consigo pensar é mock para repository e no teste de integração realmente iria subir um banco para fazer. Não daria pra usar um banco em memória, por exemplo. É isso?
@@jardeson.nogueira3100 boa pergunta! Eu uso inversão de dependência só quando realmente preciso substituir dependências. Por exemplo: chamadas entre módulos, anti-corruption layers. Como estou usando DI posso mockar o repositório sem problemas e injetar um mock ou somente métodos com stub, Typescript permite incrementar os tipos então eu faço um mock com Jest. A maioria das linguagens suportam algo similar. Para o caso do banco em memória, se eu fosse usar um eu faria, mas não acho que faz sentido teste de integração com banco em memória já que eu quero validar o fluxo por completo e o custo de subir um banco com docker é muito baixo. Acho que nunca usei um banco em memória em testes.
O bom do typeorm tem o schema separado pra não sujar as entidades. Mas eu penso que é muito difícil trocar orm, então, se não tem um Domain model, não tem complexidade pra fazer Domain model, não vai fazer teste unitário, só de integração, faz acoplado no orm mesmo. O problema é ocorrer igual o typeorm que teve uma mudança que quebrou tudo, mas ainda assim é melhor ir pelo mais simples, caso a aplicação mostre mais complexa, começa a ter muito transaction script, com service chamando services, aí é a hora de colocar um Domain model, e a parte do banco de dados fica pra gerenciar agregados, mas só se tiver complexidade pra isso. Mas as vezes não dá pra fazer isso, pq se o projeto começar de um jeito, ninguém vai querer mexer e começa a virar bagunça, é complicado essas coisas. Tem que ser o mais pragmático possível e ficar toda hora repensando as duas decisões
Pois é temos que estar sempre avaliando e ajustando. Eu entendo teu ponto de acoplar totalmente ao ORM em projetos menores, e acho que é ok mas tem que entender o impacto disso. Acoplar completamente ao ORM permite que qualquer um use qualquer método do ORM de qualquer maneira. Como falei no vídeo e um alto grau de acoplamento onde se dá muito controle. Por isso acho que com pouco esforço e possível ter uma separação que dá controle e permite evoluir.
Prefiro ORM que utiliza do padrao de Data Mapper para dar mais liberdade nas construcao do meu codigo. Ja o Active Record gera para alguns devs que estão entrando no projeto confusão. Meu projetos usamos tbm a nomenclatura de Model, acho que ajuda a não misturar com o ORM. Ja em um projeto que estou trabalhando em go estamos tentando não usar ORM deixar a coisa mais crua no SQL.
Boa Marcelo, Data Mapper é legal mesmo, facilita algumas coisas. Sobre usar SQL cru, tu usa alguma lib para segurança? Tipo injection e para compor queries?
Marcelo, vocês já deram uma olhada no SQLC? Mistura o melhor dos dois mundos, tipagem forte do modelo de banco com as questões e sql puro. Vale a pena dar uma conferida.
Haha, eu pessoalmente acho que tem um balanço entre usar sql puro e ORM, usar só SQL puro é complicado porque tu tem que escrever teu próprio ORM para fazer mapeamento, queries, proteger de injection. Mas é uma coisa pessoal né, para performance normalmente escrever a query tu mesmo é melhor. Mas mesmo fazendo SQL puro tu vai cair em uma situação similar dessa do video porque tu não vai querer ter as queries dentro da tua lógica de negócio. Como tu faz a separação do código?
Minha experiência com ORM é meio de amor e ódio. Eu curto tbm fazer o SQL puro. Sobre SQL injection, basta usar "prepared statement", a própria Lib de conexão com o banco (pelo menos nos relacionais) dão essa opção. Sobre a separação, eu simplesmente uso o SQL única e exclusivamente dentro de um repositório. Para as operações de buscar os dados no banco e montar a entidade, é basicamente isso, busca os dados e popula a entidade usando algum factory method ou uma classe factory. Usando SQL puro me da a sensação de estar no controle, sem problemas com performance e dor de cabeça com estruturas complexas de dados que complicam o entendimento de como mapear usando um ORM. Cada caso um caso.
Agora eu vi uma arquitetura bem organizada e fácil de entender! Por isso apoio e faço parte da comunidade Tech Leads Club. Alto nível de conhecimento e trazendo na prática conteúdos que podemos aplicar no nosso dia a dia :)
@@cezarmezzalira 👊🏼💎
Muito massa Waldemar, normalmente crio uma camada de entidade e uma camada de model. A camada de entidade é uma representação do meu domínio, sem nada de ORM e fica no core. E na minha camada de persistencia crie minha model. A entrada de meu repo sempre é uma entidade, e no repo faço esse parse.
Caramba, que visão sensacional e ótima didática para mostrar o caminho dos limites e o desacoplamento. Sucesso
Que visão sobre o grau de acoplamento entre as camadas, é pensando dessa forma concordo contigo pois quando deixamos de passar coisas indevidas para o CORE do negócio se perde o controle do que estão fazendo ali com essa liberdade do driver externo e sabendo limitar essa camada acaba diminuindo o acoplamento!
waldemar, o repository é um conceito simples mas conforme eu estudo mais complexo fica por ter tantas formas e opniões diferentes sobre. Por exemplo, o uso de repository em ORM Active record (eloquent, lucid do adonis etc...), vejo bastante falar que não faz sentido para esses casos e eu concordo. Outra coisa que me confunde bastante e não consigo chegar em um consenso do melhor é o uso de repository especifico ou repository generalizado. Por exemplo, o uso de repository generalizado normalemnte quebra o ISP do SOLID fazendo com que as classes implementem ou tenham acesso a métodos que elas não deveriam ter, vi formas de "driblar" isso com interface segregation (n curti) e composition (achei melhor), porém o que mais me agrada no momento é definir as interfaces específicas e criar repositórios específicos para cada entidade (to no contexto das entidades de tabela e não DDD) mas não sei se é algo bom de verdade. Outro ponto que vi comentando é que o Repository Pattern "verdadeiro" é o repository do DDD/Clean Arch com o uso das entidades de domínio, que eles possuem lógica e fazem o mapeamento das entidades pras tabelas e que o repository usando apenas com entidades de tabela da ORM (TypeORM por exemplo) na verdade sao apenas uma data access layer e não um repository real... o que você diz sobre isso tudo?
Showww as vezes eu faço o mesmo cara! Na questão do prisma a única diferença é que, eu não tenho uma (classe ou entidade model).
- Geralmente, eu crio uma interface repository para um contrato, mesmo por que as vezes preciso fazer alguns testes unitários mocados e não quero bater no banco do prisma, por isso a (interface). 😁😅
-A seguir eu crio uma classe (repository de implementação), lá eu adiciono os métodos do prisma e tudo relacionado ao ORM.
- Sigo isso, por que já houve uma situação especifica, que tive trocar todas conexão de banco para drive nativos e dessa maneira mechemos somente na camada de persistência (repository)
Ótimo conteúdo, obrigado por compartilhar.
Provavelmente terá comentários falando que é desnecessário toda essa complexidade, e que é melhor acoplar pois tbm "resolve" o problema que a tarefa está pedindo e é mais rápido, MAS provavelmente serão comentários de Devs que trabalham em projetos simples, ou que só criam o projeto e não precisam evoluí-lo, ou que nunca trabalharam em uma aplicação gigante legada para entenderem as dores que justificam essa abordagem apresentada no vídeo.
Valeu Luan, a sim, mas quem estiver em um contexto mais simples tem que usar algo simples e acoplado mesmo, mas os princípios que eu falei aqui nem são muito abstratos na verdade. Eu acho que é um nível bom de abstração para se ter ser adicionar muita complexidade.
@@WaldemarNetoDevLab sim, exato, "me de o problema que eu darei a solução". O ponto é que saber os motivos do porque de algumas estruturas serem mais complexas e do entendimento sobre acoplamento (além do grotesco getters e setters de uma entidade anêmica) é o que destrava a mente do Dev ao propor uma estrutura de projeto, principalmente quando forem começar um novo projeto, pois o jeito CRUD simples é o primeiro contato que todos os Devs tem.
Valdemar, eu vi seu vídeo de implementação do pattern repository com mongoose...se você fizesse um usando o typeorm seria INCRÍVEL! Por esse vídeo seu deu pra pegar muita coisa, mas sua explicação é muita boa e um vídeo com repository + typeorm seria maravilhoso demais.
Vou fazer então pode deixar.
@@WaldemarNetoDevLab Nuu, massa demais! Muito obrigado! Você é minha maior inspiração na área, acho muito incrível o quão dedicado e estudioso você é e tento trazer isso pra minha vida também mesmo com as complicações, quando crescer quero ser igual vc kkkkkk :)
muito bom!
Nesse caso do repository ai vc importa ele direto, não faz a inversão de dependência, como vc faz seus testes automatizados?
Nesse caso o que consigo pensar é mock para repository e no teste de integração realmente iria subir um banco para fazer. Não daria pra usar um banco em memória, por exemplo. É isso?
@@jardeson.nogueira3100 boa pergunta! Eu uso inversão de dependência só quando realmente preciso substituir dependências. Por exemplo: chamadas entre módulos, anti-corruption layers.
Como estou usando DI posso mockar o repositório sem problemas e injetar um mock ou somente métodos com stub, Typescript permite incrementar os tipos então eu faço um mock com Jest.
A maioria das linguagens suportam algo similar.
Para o caso do banco em memória, se eu fosse usar um eu faria, mas não acho que faz sentido teste de integração com banco em memória já que eu quero validar o fluxo por completo e o custo de subir um banco com docker é muito baixo. Acho que nunca usei um banco em memória em testes.
O bom do typeorm tem o schema separado pra não sujar as entidades. Mas eu penso que é muito difícil trocar orm, então, se não tem um Domain model, não tem complexidade pra fazer Domain model, não vai fazer teste unitário, só de integração, faz acoplado no orm mesmo. O problema é ocorrer igual o typeorm que teve uma mudança que quebrou tudo, mas ainda assim é melhor ir pelo mais simples, caso a aplicação mostre mais complexa, começa a ter muito transaction script, com service chamando services, aí é a hora de colocar um Domain model, e a parte do banco de dados fica pra gerenciar agregados, mas só se tiver complexidade pra isso. Mas as vezes não dá pra fazer isso, pq se o projeto começar de um jeito, ninguém vai querer mexer e começa a virar bagunça, é complicado essas coisas. Tem que ser o mais pragmático possível e ficar toda hora repensando as duas decisões
Pois é temos que estar sempre avaliando e ajustando. Eu entendo teu ponto de acoplar totalmente ao ORM em projetos menores, e acho que é ok mas tem que entender o impacto disso. Acoplar completamente ao ORM permite que qualquer um use qualquer método do ORM de qualquer maneira. Como falei no vídeo e um alto grau de acoplamento onde se dá muito controle.
Por isso acho que com pouco esforço e possível ter uma separação que dá controle e permite evoluir.
Video Muito bom, qual tema do vscode vc usa ?
@@VictorBentesDev Monokai!
Incrível como o ts ta parecido com c# :)
TS é um mix de C# e Java mesmo haha.
Prefiro ORM que utiliza do padrao de Data Mapper para dar mais liberdade nas construcao do meu codigo. Ja o Active Record gera para alguns devs que estão entrando no projeto confusão. Meu projetos usamos tbm a nomenclatura de Model, acho que ajuda a não misturar com o ORM. Ja em um projeto que estou trabalhando em go estamos tentando não usar ORM deixar a coisa mais crua no SQL.
Boa Marcelo, Data Mapper é legal mesmo, facilita algumas coisas. Sobre usar SQL cru, tu usa alguma lib para segurança? Tipo injection e para compor queries?
@WaldemarNetoDevLab golang temos pgx com scan para SQL cru.
Marcelo, vocês já deram uma olhada no SQLC? Mistura o melhor dos dois mundos, tipagem forte do modelo de banco com as questões e sql puro. Vale a pena dar uma conferida.
@@kahXimiro ouvi falar um pouco sobre. Vou testar obrigado
eu só uso orm pq as empresas usam, nos meus projetos é sql puro mesmo
Haha, eu pessoalmente acho que tem um balanço entre usar sql puro e ORM, usar só SQL puro é complicado porque tu tem que escrever teu próprio ORM para fazer mapeamento, queries, proteger de injection. Mas é uma coisa pessoal né, para performance normalmente escrever a query tu mesmo é melhor.
Mas mesmo fazendo SQL puro tu vai cair em uma situação similar dessa do video porque tu não vai querer ter as queries dentro da tua lógica de negócio. Como tu faz a separação do código?
Minha experiência com ORM é meio de amor e ódio.
Eu curto tbm fazer o SQL puro. Sobre SQL injection, basta usar "prepared statement", a própria Lib de conexão com o banco (pelo menos nos relacionais) dão essa opção.
Sobre a separação, eu simplesmente uso o SQL única e exclusivamente dentro de um repositório.
Para as operações de buscar os dados no banco e montar a entidade, é basicamente isso, busca os dados e popula a entidade usando algum factory method ou uma classe factory.
Usando SQL puro me da a sensação de estar no controle, sem problemas com performance e dor de cabeça com estruturas complexas de dados que complicam o entendimento de como mapear usando um ORM.
Cada caso um caso.
Nesse sentido, achei o Dapper um "micro ORM" simples que permite o melhor dos dois mundos.