Obrigado
@SimonMuran!!! Sei que você gosta muito de Yu-gi-oh! assim como eu.
Sobre o projeto, estou um bom tempo sem gravar videos de atualização, mas é por uma boa causa.
As duas ultimas atualizações do projeto foram bem custosas e demoradas. Estava ficando cada vez pior...
O motivo de tudo isso, é que comecei o projeto que nem um maluco, programando sem parar.
Por diversas vezes, tentei introduzir o teste unitário de código no projeto, e até consegui, mas em apenas 20% das classes.
Os testes ajudam muito, mas não fazem mágica se a arquitetura de código e design de classes não estiver bem feita, e era exatamente esse o caso.
Uma das funcionalidade do Yu-gi-oh! e que tenho no game funcionando, é a de escolher um monstro em campo e deixa-lo em modo de defesa.
O fluxograma desse script é esse:
- Retângulos são classes
- Círculos são métodos (funções)
- Setas indicam o fluxo de comunicação entre eles.
Tudo começa na classe Cursor (que é onde o jogador navega pelo campo de batalha até escolher o monstro ou qualquer carta).
A classe Cursor chama diversas classes (Battle_Field, Scene_BattleCard, Window_CardAction, etc) até chegar na classe final (Card) que vai chamar o método "to_def" e finalmente deixar aquele monstro em modo de defesa.
Quem está atento, percebeu que algo não está certo...
A classe Battle_Field
chama diversas outras classes e métodos até votar para ela mesma. Marquei essa anomalia em vermelho na imagem abaixo:
Tá! Mas qual é o problema nisso?
O grande acoplamento entre classes para executar uma única função, acaba deixando o código muito mais difícil de ser alterado, e isso acontece com todas as linguagens de programações do mundo, pois é um problema de design de código.
Nem o melhor teste unitário do universo, vai te salvar disso.
Os problemas que isso traz, são:
- Ao alterar uma função, você vai impactar todas as classes que estão ligadas a ela (quebra de código em massa);
- Ao testar unitariamente uma função, você terá depender de várias outras classes. Isso deixa os testes gigantes, complexos e ainda mais demorados de serem construídos. (Lembre-se de que quando você mexe no código, também precisa mexer no teste, quanto mais classes a sua função passar, maior vai ser o seu teste);
- Quebra do principio de responsabilidade única. Cada classe deve fazer apenas uma coisa, e somente aquilo.
- Classes dependendo de respostas de outras para executar uma ação própria [!]Cada classe deve ser responsável por gerenciar ela mesma, sem depender de outra.
O problema que estou passando no game, é exatamente esse. Qualquer funcionalidade nova que tento adicionar, demora horrores, e quebra outras funcionalidades.
Uma das classes do projeto (link abaixo), tem mais de 46 métodos públicos, isso é péssimo, pois ela está fazendo muito mais coisas do que deveria.
Esses 46 métodos são chamados por outras classes, e quando eu altero 1 desses métodos, todas essas classes quebram.
O ideal, seria essa classe ter perto de 1 a 5 métodos públicos, ela seria menor e poucas classes dependeriam dela:
Official game repository of Fan Game - Yu-gi-oh! The Curse of Past - yugioh/Battle_Field.rb at master · rogesson/yugioh
github.com
Chegou em um ponto que não consigo avançar sem refatorar todo o código existente.
Depois de voltar para o caderno, consegui desenhar um fluxo muito mais limpo, simples e elegante para a chamada do método "to_def", agora eu posso editar o código e deixar igual ao desenho (coisa que eu devia ter feito antes mesmo de iniciar a codificação).
Repare que na versão final, o fluxo ficou muito mais limpo, se já estava complexo de entender por imagem, imagina por código?
Agora, cada método é chamado pela sua classe responsável:
1) Battle_Field - Faz a leitura do evento de OK em uma carta e chama o Window_CardAction;
2) Window_CardAction - Executa o método open_card_action para exibir as ações que podem ser feitas nessa carta
3) Card - faz a leitura da opção escolhida no "open_card_action" (que no caso é a de colocar um monstro em modo de defesa) e chama o método to_def da classe Card.
Com isso, aprendi que é muito importante desenhar o fluxo de comunicação entre suas classes antes criar o código, isso em qualquer linguagem de programação!
Ainda vou levar um tempo para refatorar todo o código que está nessa situação, mas depois isso, o desenvolvimento será muito mais rápido, fácil e simples.
Em breve, volto com novidades o/