<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Pedro</title>
    <description>The latest articles on DEV Community by Pedro (@odevpedro).</description>
    <link>https://dev.to/odevpedro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F514890%2Fb7261551-b13a-4dac-bd1d-3329e8b27819.jpeg</url>
      <title>DEV Community: Pedro</title>
      <link>https://dev.to/odevpedro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/odevpedro"/>
    <language>en</language>
    <item>
      <title>Criando um simulador de duelos na web</title>
      <dc:creator>Pedro</dc:creator>
      <pubDate>Wed, 11 Mar 2026 20:39:28 +0000</pubDate>
      <link>https://dev.to/odevpedro/criando-um-simuladore-de-duelos-na-web-3kmg</link>
      <guid>https://dev.to/odevpedro/criando-um-simuladore-de-duelos-na-web-3kmg</guid>
      <description>&lt;p&gt;Como citei no artigo anterior &lt;a href="https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--1oh9"&gt;artigo 3&lt;/a&gt; criei o projeto de organização de decks apenas com o intuito simples de colocar em prática os aspectos técnicos que geralmente são demandados nas entrevistas de emprego. E também porque gosto de codar nessas horas vagas. Por mais que eu tente assumir uma postura de responsabilidade com o código desse side-project é nele que acabo me permitindo errar sem as consequências diretas de um war-room inesperado ou alguma bronca no fim do dia.&lt;/p&gt;

&lt;p&gt;Do ponto de vista do back-end, o projeto se encontra em um nível de maturidade bastante interessante. Tenho serviços com domínios bem definidos que trabalham de forma individual sem acoplamento e seguindo os principais microservices patterns. A aplicação é disposta de acordo com as práticas sugeridas pela arquitetura hexagonal.&lt;/p&gt;

&lt;p&gt;Assim que eu estava desenvolvendo o community-service(uma das partes integrantes do projeto que permite encontrar jogadores através do recurso de geolocalização) e o vi funcionando na prática, tive a ideia de estender esse projeto. Essa situação me fez lembrar de quando jogava Yu-Gi-Oh! Nos simuladores de código aberto, como edo-pro, ygo-pro, entre outros. Lembro que era possível criar um host de uma sala com regras personalizadas, mas não era possivel delimitar o range para encontrar um duelista. Isso era uma das opções de que sempre senti falta.&lt;/p&gt;

&lt;p&gt;Então pensei que seria interessante integrar o "community-service" que desenvolvi, dessa forma poderíamos então encontrar pessoas próximas que também jogam, dando um maior senso de comunidade durante a gameplay. Imediatamente baixei as versões mais usadas atualmente e fiquei um tanto descontente com o visual. Esses simuladores pareciam parados no tempo, especificamente em 2010, sem mudanças significativas de UX. Resolvi então investigar a viabilidade de criar um sistema de duelos online para se integrar não somente com o community-service, mas também com os outros serviços que eu havia desenvolvido no monorepo.&lt;/p&gt;

&lt;p&gt;E é aqui que entra o uso do Claude Code para agilizar as coisas. Lembrei desse post aqui que vi no &lt;a href="https://x.com/Dimillian/status/1993338066552123800um" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;: um teste interessante usando de uma carcaça de card-gaming, pesquisando mais a fundo encontrei também esse &lt;a href="https://blog.jacobstechtavern.com/p/i-turned-you-into-a-trading-card" rel="noopener noreferrer"&gt;artigo &lt;/a&gt;referente a um projeto que lida com efeitos semelhantes.&lt;/p&gt;

&lt;p&gt;E a maior maior referência visual que me inspirei, foi o &lt;a href="https://poke-holo.simey.me/" rel="noopener noreferrer"&gt;poke-holo&lt;/a&gt; onde os efeitos de holografia são implementados com maestria para as cartas do Pokémon OCG.&lt;/p&gt;

&lt;p&gt;É importante falar do Claude porque foi graças a essa ferramenta que entendi os requisitos necessários para implementar esse sistema de duelos. Descobri que as diferentes versões dos simuladores gratuitos usam um core único, o ocgcore, que é feito inteiramente em C++ sendo os cards escritos em lua. link do projeto: &lt;a href="https://github.com/knight00/ocgcore-KCG" rel="noopener noreferrer"&gt;ocgcore-KCG&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Esse core funciona como um processo/servidor. Cada ação do jogador vira uma mensagem binária enviada pro core, e o core responde com o novo estado do jogo. O front é essencialmente um renderer burro que exibe o que o core manda.&lt;/p&gt;

&lt;p&gt;Basicamente ele é um motor C++ que carrega as regras oficiais de Yu-Gi-Oh, o mesmo usado pelo YGOPro/EDOPro. Ele roda num servidor separado e se comunica via protocolo binário sobre WebSocket. Dessa forma a comunicação com a minha aplicação front vai se dar da seguinte maneira:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uo0t50t9j658phc3ydx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5uo0t50t9j658phc3ydx.png" alt=" " width="800" height="139"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Obs: Decidi em deixar o front como react para fortalecer os estudos recentes que tenho feito desse framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O duel-system vai ser um serviço isolado do  deck-management(mas que usará seus recursos), um sistema web feito em Java/Spring Boot que vai intermediar a comunicação entre o react e o core em C++. Basicamente ele entraria em ação com a biblioteca JNI (Java Native Interface) que vai me permitir chamar funções nativas do ocgcore. O fluxo seria esse aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wzdwduu58lnpiaqgs5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wzdwduu58lnpiaqgs5k.png" alt=" " width="292" height="327"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse ponto, acabei tendo um salto muito grande, do ponto de vista do escopo da atuação. Passei da ideia de projetar o  deck-management não apenas como um fim em si mesmo, mas como um meio facilitador de um novo sistema web de duelos. Pretendo torna-lo um sistema tão completo que sinceramente acredito numa recepção bastante positiva da comunidade.&lt;/p&gt;

&lt;p&gt;link do repositório, apenas uma poc inicial contendo o front-end em react, ainda sem a implementação do core em C++: &lt;a href="https://github.com/odevpedro/yu-gi-oh-deck-management-front-end" rel="noopener noreferrer"&gt;deck-management-front-end&lt;/a&gt; &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>react</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Criando uma arquitetura de microsserviços para organização de decks Yu-Gi-Oh com Spring Boot – Parte 03</title>
      <dc:creator>Pedro</dc:creator>
      <pubDate>Sun, 01 Mar 2026 22:48:02 +0000</pubDate>
      <link>https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--1oh9</link>
      <guid>https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--1oh9</guid>
      <description>&lt;h2&gt;
  
  
  Jogando fora tudo aquilo que eu tinha feito.
&lt;/h2&gt;

&lt;p&gt;Recentemente consegui focar bastante nesse meu projeto e, por conta disso, consegui observar com calma os erros que acabei cometendo ao longo do caminho. A ideia de iniciar esse projeto ocorreu num período em que era urgente ter ao menos um resquício de portfólio apresentável, em outras palavras: eu estava desempregado. &lt;/p&gt;

&lt;p&gt;Essa foi uma forma que encontrei para "mostrar trabalho" para os avaliadores que fossem julgar meu perfil. Dado o contexto das entrevistas em que eu estava participando, minha mente estava fortemente direcionada à orientação a objetos e à arquitetura hexagonal. E tudo isso era muito teórico no momento então resolvi colocar em prática, mas a afobação acabou falando mais alto.&lt;/p&gt;

&lt;p&gt;De início, pensei em dois serviços apenas: o organizador de decks e outro serviço que seria responsável por organizar as cartas. Acontece que, antes de pensar em modelar o principal recurso que a minha API oferece: a organização de decks, acabei focando nas unidades que compõem um baralho: as cartas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refatorando card-service:
&lt;/h2&gt;

&lt;p&gt;Foi muito legal pensar sobre como era composta uma carta, fazer toda aquela estruturação inicial das classes, criar um modelo abstrato de cards e ter os outros tipos estendendo diretamente dela. Além disso, houve todo o processo de criar as tabelas no banco, lidar com as migrations na prática etc. &lt;/p&gt;

&lt;p&gt;Enfim, escrevi muito código que precisei jogar fora, mas foi necessário. Sinceramente, essa foi uma experiência interessante para tornar evidente o fato de que não podemos nos apegar ao código, mas sim à solução. Não foi fácil fazer isso, já que eu acabei me apegando às primeiras versões da aplicação e da progressão que estava acontecendo nos dois primeiros artigos.&lt;/p&gt;

&lt;p&gt;Mas agora preciso admitir que estava quase tudo errado. Isso porque a entidade CARD não fazia o menor sentido dentro do card-service, já que esse módulo da aplicação serve apenas como um meio pelo qual o serviço de deck usa para realizar as buscas das cartas, dessa forma não há justificativa para a persistência em um banco de dados. &lt;/p&gt;

&lt;p&gt;Agora, card-service é apenas um recurso de consultas na biblioteca de cartas do Yu-Gi-Oh! Que abrange diversos filtros, é o serviço mais leve do projeto até agora. Segue o fluxo do seu funcionamento:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2rxnxvt2ip8ooids60c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd2rxnxvt2ip8ooids60c.png" alt=" " width="800" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O serviço de deck segue na mesma intenção anterior: ser uma coleção de cartas, a diferença é que agora essas CARTAS são reconhecidas por seus IDs e não por suas entidades do banco de dados. Já que o card-service permite a consulta de múltiplas cartas por id, então o front-end consegue renderizar as cartas na tela batendo diretamente nesse endpoint.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  card-creator-service:
&lt;/h2&gt;

&lt;p&gt;A fim de implementar event driven architecture(EDA), resolvi criar um novo microservice: card-creator-service(que agora não é simplesmente um endpoint em cards-service). Um serviço que nos permite criar novas cartas customizadas seguindo todas as especificações de composição de card. A mensageria aqui vai entrar juntamente com a ideia de validar/autorizar a criação daquela carta. O fluxo seria: o usuário cria uma carta e ela surge com o status pendente: esperando a avaliação do serviço que vai inferir a viabilidade da carta, dizendo se ela é aceitável. Este serviço vai se chamar konami-validator-service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1im6caafj7bdtr9so2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1im6caafj7bdtr9so2r.png" alt=" " width="800" height="586"&gt;&lt;/a&gt;&lt;br&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  shared-domain
&lt;/h2&gt;

&lt;p&gt;Shared-domain surge da necessidade de tirar a interdependência entre os microservices: é um módulo Java puro (sem Spring, sem banco, sem dependências externas) que contém apenas os enums que representam o vocabulário do universo Yu-Gi-Oh: tipos de carta, atributos de monstro, subtipos e raças.&lt;/p&gt;

&lt;p&gt;Ele existe porque múltiplos serviços precisam falar a mesma língua. Sem ele, cada serviço teria sua própria cópia de CardType, MonsterAttribute e afins, todo esse código duplicado poderia divergir o tempo. Com ele, todos importam de uma única fonte da verdade, garantindo consistência em todo o projeto sem criar acoplamento de runtime entre os serviços. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqj4ptbp3zdpf7k5ig5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqj4ptbp3zdpf7k5ig5y.png" alt=" " width="800" height="272"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqj4ptbp3zdpf7k5ig5y.png" rel="noopener noreferrer"&gt;Abri a imagem com maior resolução&lt;/a&gt;&lt;br&gt;
&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Recursos futuros:&lt;/strong&gt; Pretendo tornar esse projeto o mais over engineering possivel. A ideia é estudar os recursos que gradualmente vão sendo adicionados e ter uma implementação prática para os conceitos que geralmente são exigidos pelo mercado. Futuramente pretendo adicionar: Geolocalização, WebSocket com STOMP, Elasticsearch, etc&lt;/p&gt;

&lt;p&gt;Repositório: &lt;a href="https://github.com/odevpedro/yu-gi-oh-deck-management" rel="noopener noreferrer"&gt;github.com/odevpedro/yu-gi-oh-deck-management&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>spring</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Criando um microserviço de organização de decks Yu-Gi-Oh com Spring Boot Parte 02</title>
      <dc:creator>Pedro</dc:creator>
      <pubDate>Wed, 16 Apr 2025 19:38:17 +0000</pubDate>
      <link>https://dev.to/odevpedro/criando-um-microservico-de-organizacao-de-decks-yu-gi-oh-com-spring-boot-parte-2-2o5d</link>
      <guid>https://dev.to/odevpedro/criando-um-microservico-de-organizacao-de-decks-yu-gi-oh-com-spring-boot-parte-2-2o5d</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Neste artigo dou continuidade à construção da uma aplicação baseada em microserviços, utilizando Java e Spring Boot para gerenciar cartas e decks de Yu-Gi-Oh, com arquitetura hexagonal. Neste segundo artigo incluo o suporte multi usuário.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Recapitulando
&lt;/h2&gt;

&lt;p&gt;Na &lt;a href="https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--2ipf"&gt;Parte 1&lt;/a&gt; abordamos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modelagem baseada na orientação a objetos pura, explorando a herança entre cartas (Monster, Spell, Trap)&lt;/li&gt;
&lt;li&gt;Foi feita a integração com API externa YGOProDeck&lt;/li&gt;
&lt;li&gt;Uso do padrão de projeto factory através da classe:&lt;code&gt;CardFactory&lt;/code&gt; e &lt;code&gt;FeignClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Arquitetura Hexagonal aplicada&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agora evoluímos para:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistência com Spring Data JPA (Usando o banco de dados local h2)&lt;/li&gt;
&lt;li&gt;Criação de cartas personalizadas via &lt;code&gt;POST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Filtragem de cartas por usuário com o parâmetro &lt;code&gt;ownerId&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Endpoint de listagem exclusiva &lt;code&gt;GET /cards/custom?ownerId=&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  O Cenário Atual
&lt;/h2&gt;

&lt;p&gt;Cada carta agora carrega um campo &lt;code&gt;ownerId&lt;/code&gt;, que identifica o usuário que a criou. Isso permite separar cartas criadas manualmente daquelas importadas via API externa.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Obs: O fato de incluirmos um simples campo na nossa aplicação faz com que seja necessário alterar todas as outras estruturas que contavam com a ausência desse campo, por exemplo: o teste de persistencia não incluia esse novo campo, nosso mapper não esperava esse campo e todas as outras estruturas que fazem parte da criação e persistencia desse campo no banco de dados.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Exemplo de objeto &lt;code&gt;Card&lt;/code&gt; salvo:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99999999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Teste Dragão Sombrio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MONSTER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ownerId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user123"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Endpoints
&lt;/h2&gt;

&lt;h3&gt;
  
  
  POST /cards/custom
&lt;/h3&gt;

&lt;p&gt;Cria uma carta customizada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /cards/custom
Content-Type: application/json

{
  "name": "Teste Dragão Sombrio",
  "type": "MONSTER",
  "attack": 2500,
  "defense": 2100,
  "level": 7,
  "attribute": "DARK",
  "monsterType": "DRAGON",
  "subTypes": ["NORMAL", "EFFECT"],
  "ownerId": "user123"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GET /cards/custom?ownerId=user123
&lt;/h3&gt;

&lt;p&gt;Lista apenas as cartas criadas por &lt;code&gt;user123&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99999999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Teste Dragão Sombrio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MONSTER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ownerId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user123"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Arquitetura Hexagonal Aplicada
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domínio&lt;/strong&gt;: &lt;code&gt;Card&lt;/code&gt;, &lt;code&gt;MonsterCard&lt;/code&gt;, &lt;code&gt;SpellCard&lt;/code&gt;, &lt;code&gt;TrapCard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portas&lt;/strong&gt;: &lt;code&gt;CardPersistencePort&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapters&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CardRepositoryAdapter&lt;/code&gt; (saida)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CustomCardQueryController&lt;/code&gt; (entrada)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SaveCardUseCase&lt;/code&gt; e &lt;code&gt;ListCustomCardsUseCase&lt;/code&gt; (aplicação)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Infraestrutura&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;JpaRepository&lt;/code&gt; separados por tipo de carta&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H2&lt;/code&gt; como banco em memória&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Destaques
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Modularização limpa para cada tipo de carta&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ownerId&lt;/code&gt; como chave de multi-tenancy&lt;/li&gt;
&lt;li&gt;Separando responsabilidade por camadas (entrada, saída, domínio)&lt;/li&gt;
&lt;li&gt;Fácil evolução futura com autenticação (JWT)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Próximos Passos
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Na próxima parte, vamos abordar a criação e gerenciamento de decks personalizados com persistência e exportação em formato ydk.&lt;/li&gt;
&lt;li&gt;Criação do validador das cartas(konami) customizadas.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Repositório: &lt;a href="https://github.com/odevpedro/yu-gi-oh-deck-management" rel="noopener noreferrer"&gt;github.com/odevpedro/yu-gi-oh-deck-management&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Representação visual da nova implementação:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8dz4t2ssc82np1xr0sc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8dz4t2ssc82np1xr0sc.png" alt=" " width="800" height="187"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>java</category>
      <category>microservices</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Criando uma arquitetura de microsserviços para organização de decks Yu-Gi-Oh com Spring Boot – Parte 01</title>
      <dc:creator>Pedro</dc:creator>
      <pubDate>Thu, 10 Apr 2025 19:50:08 +0000</pubDate>
      <link>https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--2ipf</link>
      <guid>https://dev.to/odevpedro/criando-uma-arquitetura-de-microsservicos-para-organizacao-de-decks-yu-gi-oh-com-spring-boot--2ipf</guid>
      <description>&lt;p&gt;&lt;em&gt;Este documento demonstra de forma prática a aplicação do padrão arquitetural Ports and Adapters(Hexagonal) na funcionalidade de busca de cartas do jogo Yu-Gi-Oh usando a API pública &lt;a href="https://ygoprodeck.com/api-guide/" rel="noopener noreferrer"&gt;YGOProDeck&lt;/a&gt;. Seguindo as boas práticas especificadas pela arquitetura em questão: separando as responsabilidades entre domínio, entrada, saída e infraestrutura externa.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introdução &amp;amp; Objetivos iniciais do projeto
&lt;/h2&gt;

&lt;p&gt;Neste primeiro artigo venho apresentar a organização do projeto e como foi feita a modelagem do sistema. Primeiramente, vamos entender o domínio que está sendo abordado. Nas demais postagens será apresentado os outros micro serviços que compõem a aplicação e a comunicação entre eles através da mensageria.&lt;/p&gt;

&lt;p&gt;Yu-Gi-Oh! é um card game estratégico, onde jogadores constroem e enfrentam decks compostos por diferentes tipos de cartas: monstros, mágicas, armadilhas, fusões, entre outras. O jogo possui regras bem estabelecidas e possui uma variedade enorme de cartas, com diferentes efeitos, atributos e classificações.&lt;/p&gt;

&lt;p&gt;Este é um projeto feito na intenção de praticar diversos conceitos relevantes da linguagem java que são constantemente exigidos pelo mercado, nele levo em considerações temas como DDD, padrões de projetos, arquitetura de micro serviços e mensageria. O projeto está sendo feito usando o framework Spring Boot e tem como principal objetivo ser uma ferramenta de apoio para organização de decks, permitindo que o usuário:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Consulte cartas diretamente da API pública YGOProDeck&lt;/li&gt;
&lt;li&gt;Crie e salve cartas customizadas&lt;/li&gt;
&lt;li&gt;Monte decks personalizados, separados em Main Deck, Side Deck e Extra Deck&lt;/li&gt;
&lt;li&gt;Valide cartas customizadas por meio de um microserviço de integridade (KonamiService) &lt;/li&gt;
&lt;li&gt;Visualize estatísticas e receba notificações futuras (em evolução)&lt;/li&gt;
&lt;li&gt;Exporte seus decks no formado ydk.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Modelagem da Solução
&lt;/h2&gt;

&lt;p&gt;A modelagem se deu da seguinte maneira: basicamente o game é formado por um número relativamente pequeno de cartas "principais" que vão servir de base para uma série subdivisões de cartas semelhantes. Por exemplo:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff9l5y296vx4d4xff68dq.png" width="800" height="1166"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ahiytq0qrpftz5osceb.png" width="476" height="695"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3otcw4t5t3ifajmphhrg.png" width="419" height="610"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Monstro&lt;/td&gt;
&lt;td&gt;Mágica&lt;/td&gt;
&lt;td&gt;Armadilha&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqxu1oen0rqj6ptcakunf.png" width="800" height="800"&gt;&lt;/th&gt;
&lt;th&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0yd62dk0shykrf8zvlvr.png" width="620" height="437"&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Modelo abstrato card&lt;/td&gt;
&lt;td&gt;classe Java&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Considerando as chamadas de API feitas para cada um dos tipos exibidos acima, foi possivel identificar elementos em comum. Levando isso em consideração surge então a ideia de abstrair o que é compartilhado entre essas cartas em uma estrutura única. Dentro do contexto de orientação a objetos essa abordagem é conhecida como herança e foi aplicada através de uma classe abstrata chamada Card.java &lt;/p&gt;

&lt;p&gt;No artigo de hoje será desenvolvida a funcionalidade de busca externa de cartas usando OpenFeing como cliente que conta com a seguinte solução:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Fluxo da Requisição
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85yejjxv6vmfo8aww1s1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85yejjxv6vmfo8aww1s1.png" alt="Image description" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Endpoint REST - &lt;code&gt;ExternalCardController&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/cards"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExternalCardController&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;CardSearchPort&lt;/span&gt; &lt;span class="n"&gt;cardSearchPort&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ExternalCardController&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CardSearchPort&lt;/span&gt; &lt;span class="n"&gt;cardSearchPort&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cardSearchPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cardSearchPort&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/search"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;searchByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@RequestParam&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cardSearchPort&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;searchByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O controller expõe o endpoint &lt;code&gt;/cards/search&lt;/code&gt; e injeta a interface &lt;code&gt;CardSearchPort&lt;/code&gt;, que é uma porta do domínio. Ele não sabe como a busca é feita — só encaminha a requisição e retorna o resultado.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Porta - &lt;code&gt;CardSearchPort&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;CardSearchPort&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;searchByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa interface define o contrato da busca. O domínio não depende de como ou onde a busca acontece — só que ela &lt;strong&gt;deve&lt;/strong&gt; acontecer.&lt;/p&gt;




&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Implementação - &lt;code&gt;YgoProApiClient&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;JsonNode&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;feignClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCardsByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JsonNode&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;CardFactory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;ifPresent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;cards:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;YgoProApiClient&lt;/code&gt; é um adapter de saída que implementa &lt;code&gt;CardSearchPort&lt;/code&gt;. Ele usa o &lt;code&gt;YgoProFeignClient&lt;/code&gt; para consultar a API e o &lt;code&gt;CardFactory&lt;/code&gt; para converter JSON em objetos &lt;code&gt;Card&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Implementação - &lt;code&gt;CardFactory&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Aqui usamos o design pattern factory que vai criar uma instância de um objeto de acordo com o tipo especifico de dado que for coletado, por esse motivo temos os condicionais presentes na classe. E por mais verboso que possa parecer todo esse tratamento ele fica totalmente encapsulado dentro do método fromJson.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CardFactory&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fromJson&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JsonNode&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asLong&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"desc"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;archetype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"archetype"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"archetype"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"card_images"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"image_url"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Monster"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;atk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"atk"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asInt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"def"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asInt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"level"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asInt&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;MonsterAttribute&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonsterAttribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"attribute"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;MonsterType&lt;/span&gt; &lt;span class="n"&gt;monsterType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MonsterType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"race"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonsterSubType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;subTypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;detectMonsterSubtypes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;MonsterCard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;archetype&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;atk&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attr&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;monsterType&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subTypes&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Spell"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;SpellType&lt;/span&gt; &lt;span class="n"&gt;spellType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpellType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"race"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;SpellCard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;archetype&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spellType&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Trap"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;TrapType&lt;/span&gt; &lt;span class="n"&gt;trapType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TrapType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"race"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;asText&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;TrapCard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;archetype&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trapType&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Card&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"_"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"_"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonsterSubType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;detectMonsterSubtypes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;rawType&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MonsterSubType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EnumSet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;noneOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonsterSubType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rawType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toUpperCase&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MonsterSubType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusão
&lt;/h2&gt;

&lt;p&gt;Este exemplo demonstra os princípios da arquitetura hexagonal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;strong&gt;domínio&lt;/strong&gt; define a interface (CardSearchPort)&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;controller&lt;/strong&gt; é um &lt;strong&gt;adaptador de entrada&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;O &lt;strong&gt;Feign client + factory&lt;/strong&gt; são &lt;strong&gt;adaptadores de saída&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esse modelo permite evoluir ou trocar qualquer parte da aplicação sem afetar o restante, promovendo testabilidade e manutenibilidade.&lt;/p&gt;

&lt;p&gt;Repositório do github para consulta: &lt;a href="https://github.com/odevpedro/yu-gi-oh-deck-management" rel="noopener noreferrer"&gt;https://github.com/odevpedro/yu-gi-oh-deck-management&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>java</category>
    </item>
  </channel>
</rss>
