A próxima conversa com Pixonic DevGAMM Talks, que deciframos, é um pouco filosófica - esse é um discurso de Konstantin Gladyshev. Ele foi o programador líder de jogos da 1C Game Studios e falou sobre o princípio de gerenciar a complexidade do desenvolvimento no contexto de todo o produto, e não sobre os recursos individuais. E com exemplos, ele mostrou por que o principal no desenvolvimento é determinar o que não deve ser feito. Para outros relatórios, leia os links no final do artigo.
Eu queria falar sobre o norte, mas decidi fazer um relatório filosófico sobre o que deveria ser feito mais facilmente. Trabalhei no Postal III, Indestrutível, Robôs de Guerra e atualmente estou fazendo o Caliber, um jogo de tiro online da 1C e da Wargaming.

Por que decidimos conversar sobre o KISS (seja simples, estúpido)? Porque mesmo os idosos com 20 anos de experiência ou CTO frequentemente continuam esculpindo e inventando alguma coisa. Mas você precisa fazer isso com mais facilidade. De fato, há mais sobre YAGNI (você não precisa disso) e um pouco de filosofia.
Devo dizer imediatamente que não estamos falando de soluções completamente idiotas, como "encontrar x", estamos falando de soluções mais ou menos simples.

Por que às vezes é muito difícil? Tudo começa com boas intenções e elas, como você sabe, levam ao inferno. Aqui está uma história em quadrinhos sobre isso.

Os motivos para isso são aproximadamente os mesmos, mas os chamei de maneira diferente:
- Soluções universais . Existe algum tipo de recurso e nós imediatamente criamos uma biblioteca, um milhão de casos adicionais. E de repente nosso atirador se transformará em uma fazenda? Ou "da próxima vez farei outro exatamente o mesmo atirador". É improvável que isso mude para você.
- Prova do futuro . Quase a mesma coisa - esses são problemas inexistentes. "E se eu tiver um milhão de usuários imediatamente, preciso suportar 22 servidores intermediários?" etc. Para começar a ganhar, um servidor é suficiente para você.
- Usando as ferramentas erradas . Quando você usa ferramentas que não se encaixam e persistem na sua ilusão.
- E todo mundo conhece otimização prematura .
Tivemos um exemplo quando eles fizeram o Caliber. Os caras que estavam nos ajudando decidiram fazer um superserializador imediatamente no C ++ mais recente.
Como resultado, não funcionou como desejado, era inconveniente enviar um estado parcial, porque os modelos não entendem realmente onde é necessário, onde não é, ou se você faz alguns sinalizadores. Os erros que estavam nesse código padrão, mesmo o autor não entendeu ao longo do tempo.

Em seguida, um dos programadores em apenas duas horas reescreveu tudo isso em uma página do código C, que fez exatamente o que precisávamos naquele momento. E funcionou maravilhosamente.
Outro exemplo Tínhamos o Postal III e foi feito no mecanismo Source. Existe um mundo tão aberto que você pode andar entre mapas, uma câmera de terceira pessoa, muitas casas térreas de estilo americano com janelas, robôs podem correr e entrar em pânico em portas abertas. Como resultado, o BSP inteiro não funcionou. Foi considerado por muito tempo, por causa das janelas resultou em um milhão de setores e ainda não fez nada. Foi preciso muita memória e carregado por um longo tempo.

O Half-Life, para o qual o motor foi fabricado, é um jogo de tiro em primeira pessoa e, a partir do terceiro, era inconveniente fazer algumas coisas. Tudo o que era útil do Half-Life não nos convinha. Além disso, uma grande quantidade de animação deveria ser feita, porque de uma terceira pessoa você precisa subir, etc. Era necessário trocar o motor, mas não havia opção.
O que fazer quando tudo está ruim, difícil, mas eles nos pressionam? Primeiro, executar os recursos na ordem certa, porque otimizar antecipadamente é um dos problemas. Alguns começam a colar strassiks antes de costurar o vestido e depois não podem costurar, porque os straziks interferem.
Primeiro, faça o chip mais simples para que funcione, depois estabilize e depois otimize. É nessa ordem que todo o resto está errado.

Por visualização, entendemos que é minimamente operacional, ou seja, MVP (produto mínimo viável).

Então você avalia seu potencial. Suponha que os criadores de jogos apresentem recursos, o programador recorra e diga "Eu vou bem, não vou fazer mal, então desenhe imediatamente um design de jogo descolado". Mas como ele sabe? Ele não jogou, não sabia se era bom ou ruim. Portanto, idealmente, você cria um recurso, reproduz, se normal, e depois o faz. Não é normal - jogado fora, nem uma pena.
Há mil anos, Sun Tzu disse que vencer 100 batalhas não é o pico, o pico é vencer sem uma batalha. I.e. não faça o que você não pode fazer.
Estabilização. Você criou recursos e o estabilizou ainda mais sem acréscimos desnecessários. Você precisa de uma roda em uma árvore, em uma corda? Está pendurado. Nada mais.

Consequentemente, se de repente se descobrir (sem nenhuma prova futura) que o recurso deve mudar - inicie novamente. Apenas protótipo, estabilize e não tente adivinhar. Você ainda não vai adivinhar.
Bem, otimização prematura. Isso é sempre ruim. Você precisa otimizar no final, quando tiver certeza de que esse recurso é importante, ele deve ser otimizado e não será alterado fundamentalmente no futuro próximo.

Porque a otimização é um conjunto de casos especiais. A legibilidade do código piora, as abstrações quebram e a portabilidade, como regra, também piora bastante.

Este é um deslize provocativo, porque as muletas são realmente ruins. Mas aqui a situação é mostrada quando há vários recursos e protótipos sem graça, tudo está ruim e parece que tudo entrará em colapso. Mas isso não é verdade. Veja - esta é a cofragem, o concreto é derramado e as “muletas” são sustentadas enquanto seca. I.e. Se a situação for absolutamente normal, as “muletas” serão removidas, mas não imediatamente, sem pânico.
Brevemente sobre filosofia. Não há soluções universalmente válidas. Não tente criar uma estrutura com 100 anos de antecedência ou para todas as ocasiões.

Melhor fazer um monte de pequenos pedaços que fazem seu trabalho bem. Jogue fora o desnecessário o mais rápido possível, não tente apoiá-lo. E ao escrever um código, torne explícito. Às vezes, é melhor escrever um código explícito que você serializa com as mãos, em vez de refletir ou algo mais. Usar uma ação de dependência quando você não precisar também é uma má ideia. É muito difícil de ler, metade dos erros em tempo de execução. Explícito é melhor que implícito. E torne o mais simples possível evitar erros quando alguém não entende alguma coisa ou até se esquece completamente.
Como Bruce Lee disse, a simplicidade é o mais alto grau de arte. Certa vez, um ator a quem ele ensinou seu Jeet Kune-Do perguntou: "Qual é a essência da sua arte marcial Jeet Kune-Do?" Naquele momento, Bruce Lee deixou cair a carteira, o ator a pegou e Bruce Lee disse: "Veja, você apenas se abaixou e pegou a carteira, e se você estivesse na pose de um cavaleiro, feito kata, nunca a teria levantado".
Perguntas da platéia
"Você disse que a otimização prematura é má." Vale a pena escrever testes prematuros quando um projeto está apenas começando?- No meu entender, tudo prematuro é prejudicial. Nos testes, não sou muito forte, porque no desenvolvimento de jogos (em muitos casos), os testes estão mais próximos do final do desenvolvimento. No começo, tudo muda tão rapidamente que enquanto você está escrevendo um teste, o designer do jogo já muda tudo. Acredito que é ruim gastar energia em um teste do que mudará em duas horas. Isso deve ser feito no estágio de estabilização. Mas não na fase do protótipo. Mas se a equipe puder escrever testes rapidamente, isso provavelmente é bom. Se não, então não.
- Você mencionou que as muletas serão removidas, mas há uma tese maravilhosa - não há nada mais permanente do que temporário. Todos trabalhamos no desenvolvimento de jogos, temos prazos, produtores, um novo recurso e assim por diante. Quantas vezes você já viu uma situação em que limpava muletas? E eles os levaram a zero?- Provavelmente não em zero. Se o projeto estiver ativo, você sempre terá muletas. Tudo funciona se eles forem limpos sistematicamente. I.e. Você fez um recurso - gravado imediatamente.
- I.e. Um certo processo deve ser construído na empresa? Tipo de fase oficial de limpeza da muleta?- Sim, acredito que isso deve ser incluído na tarefa. I.e. se você precisar refatorar no processo da tarefa - refatorar. Grosso modo, mesmo a palavra refatoração não é - está dentro da tarefa.
- Você consegue fazer isso na prática? Você vem ao produtor e diz ao planejar uma nova iteração que precisamos de duas semanas para limpar, refatorar etc. E ele diz que o valor comercial é zero, agora apresentamos x, e você o limpará mais tarde, depois do trabalho. Como estar nesta situação?- Nós conseguimos. O produtor está ciente de que há algumas dívidas que você está corrigindo, mas em tempo hábil. Não que você tenha um novo lançamento, ele não possui um único recurso, mas aqui está algum tipo de refatoração. Basta escolher o produtor certo.
"Com a experiência, a compreensão vem, quanto mais simples, melhor." Mas programadores iniciantes tentam criar sistemas complexos, assustadores, grandes e gigantescos. Pergunta: como mantê-los disso, exceto por um "não" difícil?Acho que isso é um problema de aprendizado. É necessário mostrar o mais cedo possível quais soluções funcionam, quais não e por quê. Quando você tem experiência e pode explicar por que não precisa fazer isso, basta dar muitos exemplos e ele já funciona bem. Mostrar e monitorar constantemente com seu próprio exemplo, para que tudo seja simples. Coloque protótipos para que eles reescrevam com mais frequência. Quando você reescreve frequentemente, não gosta de escrever muito e eles escrevem de maneira cada vez mais simples.
- Se já existe algo muito complicado que é usado em vários projetos, e essa complexidade não ajuda mais, mas interfere - como é fácil mudar para soluções simples?- Minha opinião é, apenas comece a fazê-lo novamente. Idealmente, uma equipe separada, desde o início. Provavelmente você recuperará 80% da funcionalidade muito rapidamente. Em uma biblioteca nova e limpa. E então você alcançará.
- Por exemplo, existe um poderoso serializador e editor de lógica de jogos, agora está bastante desatualizado ...- Essas são as mesmas ferramentas inconvenientes. Tome confortável. Unidade, por exemplo.
- Diga-me, qual é o seu planejamento no código, qual é o detalhamento? O programador principal resolve todos os problemas menores, todas as tarefas?- Temos uma tal anarquia, uma estrutura bastante plana, não muita gente. Confiamos em todos e simplesmente distribuímos quem pegará o protótipo e quem não pegará. Pode ser qualquer pessoa arbitrária.
Mais conversas com o Pixonic DevGAMM Talks