Há tempos amigos, clientes, fornecedores e leitores do blog pedem pra postarmos um caso de sucesso. Isso é um negócio complicado porque temos que, além de escrever o case, ter a autorização do cliente, além de escrever com toda a transparência para que o case faça sentido, mas sem mostrar informações confidencias do projeto ou do cliente. Passadas todas as fases, temos o case do gerenciador de downloads que fizemos para a Level Up!, e o que estava pegando a algum tempo era o tempo pra parar e escrever um case direito. Aqui está ele, finalmente. Antes de mais nada agradeço aos nossos parceiros da Level Up! por terem nos autorizado a escrever o case, e ao pessoal da Lambda3 pra me ajudar a compilar informações sobre o projeto e o produto.

O que faz é o gerenciador de downloads?

A Level Up! traz para o Brasil diversos jogos, com uma grande adoção no país. Aqui vocês entendem um pouco mais sobre a empresa. No seu portfólio estão Allods, Lunia, Ragnarök, Grand Chase, entre outros. Esses jogos devem ser baixados para que possam ser jogados. Cada um deles tem seu próprio instalador, e alguns deles podem ser baixados diretamente ou via torrent. O legal do download via torrent é que o usuário tem uma banda muito maior disponível, já que se os servidores de download ficarem sobrecarregados, os outros usuários continuam a compartilhar os dados. Além disso, isso descarrega os servidores de download. Só que nem todos os usuários estão acostumados com a ideia do torrent ou tem um cliente de torrent instalado, e mesmo os que estão acostumados muitas vezes preferem por comodidade usar o download normal.

A Level Up! teve a ideia de criar um gerenciador de downloads que facilitasse o uso do download com torrents, além de gerenciar também as atualizações e a abertura do jogo.

Aqui vocês veem o gerenciador rodando (clique para ampliar):

Gerenciador de downloads - 2Gerenciador de downloads - 2Gerenciador de downloads - 3

Para experimentar o gerenciador de downloads basta baixar um jogo. Aqui você encontro o download do Allods, mas outros jogos, como o Lunia e o Combat Arms também o utilizam.

A tecnologia

Como os jogos são feitos pra Windows a ideia era fazer algo com .NET. O WPF foi a tecnologia escolhida por diversos motivos, como facilidade de desenvolver uma interface rica, suportar um bom padrão de separação de responsabilidades na interface gráfica via MVVM, estar presente na maioria das máquinas com Windows, ser uma tecnologia moderna e recomendada pela Microsoft e ter uma tonelada de componentes pagos e open source que complementam o desenvolvimento.

Atualização automática

A ideia era que o gerenciador se atualizasse sozinho, e isso é mais uma coisa que o .NET traz de graça a muitos anos. Com ClickOnce pudemos permitir que a aplicação se instale e atualize automaticamente. Ao abrir o instalador a aplicação é instalada, e se lembra de onde veio. A partir daí, sempre que você abre ela de novo verá essa tela de update, que abre e fecha muito rápido:

Verificando atualização com clickonce

Caso encontre uma atualização ele apresentará a opção de instalação ou fechar.

Após instalado, o gerenciador fica disponível no menu de start, como uma aplicação normal:

App instalada no Start Menu

O ClickOnce é sem dúvida uma excelente opção para o cenário que se propôe a atender.

Baixando Torrents

O gerenciador baixa torrents e instala os jogos baixados. Para isso precisaríamos programar um cliente de torrents, e não tínhamos a intenção de fazer isso do zero. Após bastante pesquisa descobrimos diversos componentes que permitiam baixar torrents, mas nenhum nos satisfez como o MonoTorrent. É um componente bem enxuto e fácil de usar, e, apesar de ter ainda espaço para melhorar, atendeu razoavelmente bem às nossas necessidades. Infelizmente não houve um segundo lugar próximo, temos uma enorme falta de bons componentes para gerenciar e baixar torrents com .NET. O MonoTorrent permite baixar, pausar, reiniciar, e cancelar o download, além de fornecer uma série de informações e estatísticas sobre o download (além de diversas outras funcionalidades).

Encontramos um pequeno bug no componente na maneira com que ele lida com webseeds e restaura conexões perdidas, mas como ele é open source pudemos corrigi-lo e vamos submeter um patch com a correção para os desenvolvedores originais. Recomendamos fortemente que, se você precisar gerenciar downloads de torrents, utilize o MonoTorrent. Em meia hora brincando com ele você monta um gerenciador de torrents simples. Depois coloco aqui no blog o código de umas provas de conceito que fizemos com ele antes de adotá-lo.

Separando responsabilidades com MVVM

Não vou explicar o que é MVVM aqui, porque foge ao escopo do que queremos falar, e há bastante informação na web. De qualquer forma, escolhemos o MVVM por ele se encaixar muito bem com WPF. Na prática o MVVM é um Presentation Model um pouco diferente e adaptado para o WPF (e apps XAML em geral). E é muito bom usar MVVM com WPF porque há um grande suporte da comunidade com projetos open source que entregam componentes complementares ao WPF para tornar o desenvolvimento mais fácil. No nosso caso, optamos por Caliburn, que é um projeto maduro e bastante adotado. Mas calma, se você estiver procurando um componente para MVVM você vai ficar mais feliz com o Caliburn.Micro. Só não adotamos o Caliburn.Macro porque o framework alvo era .NET 3.5, e ele não o suporta.

Poderíamos ter adotado MVC junto ao WPF, e, ainda que seja um excelente padrão arquitetural para interface gráfica, estaríamos trabalhando de forma muito diferente do que o mercado em geral trabalha, tendo que reimplementar na mão boa parte do código que componentes de MVVM disponíveis já implementam. Pesando as diferenças e avaliando esse apoio da comunidade, do mercado, e o suporte com bons componentes, a escolha pelo MVVM foi natural.

Testando com White

Na Lambda3 nós não fazemos código sem testes automatizados. E uma boa parte dos testes é feita de forma integrada, queremos passar por toda a aplicação e garantir que ela funciona. No caso de uma aplicação WPF isso significa abrir a aplicação, clicar em alguns widgets e verificar que ela se comportou conforme o esperado. Não há uma grande gama de componentes de testes que são capazes de automatizar o WPF, e após procurar bastante encontramos o White. O White não automatiza só WPF, mas também quase qualquer aplicação com interface gráfica no Windows. Tirando poucos casos ele nos atendeu muito bem, facilitando bastante o trabalho. Hoje, ao rodar a suíte de testes vemos a aplicação subir, realizar diversas atividades e temos um resultado verificável no final, com um sinal verde se o teste passou ou vermelho se falhou. Tudo isso em pouco segundos.

Testando com TDD e BDD

É bom lembrar que também fizemos testes de unidade. Na verdade os testes começaram com especificações escritas com SpecFlow e BDD, e, com outside-in fomos entrando e caímos eventualmente no TDD. Lá utilizamos Moq de vez em quando para separar algumas dependências.

Subindos componentes pro Nuget e devolvendo pra comunidade

Estava muito claro desde o começo do projeto de que iríamos adotar o Nuget para gerenciar nossas dependências. No entanto, algumas delas não estavam no Nuget. No caso do Monotorrent nem mesmo os binários estavam disponíveis. Como tivemos que baixar e compilar tudo, nada mais natural do que subir os componentes pro Nuget e facilitar a vida do resto da comunidade. Hoje você encontra nugets do Monotorrent, White, XStream.NET (dependência do White), Caliburn e Caliburn.Windsor no Nuget, resultados deste projeto, que subimos pro Nuget. Os commiters dos projetos foram avisados e alguns deles assumiram a responsabilidade pelos pacotes, outros não.

Este é um comportamento comum na Lambda3: sempre que precisamos de um componente e ele não está no nuget (ou RubyGems, etc), nós subimos eles e repassamos pros owners. Recomendamos fortemente que vocês façam o mesmo. De presente vocês ganham um componente com dependências gerenciadas automaticamente, e centenas de pessoas agradecidas. Note os componentes que listamos e verão que muitos deles foram baixados centenas de vezes.

O processo de desenvolvimento

Na Lambda3 nenhum projeto é feito com escopo, prazo ou custo fechado. Nascemos ágeis e sempre seremos ágeis. Esse projeto não foi exceção. A Level Up! já buscava fazer o projeto de forma ágil e tivemos então um belo casamento de expectativas.

Sempre mantivemos o time da Level Up! ciente do que estava acontecendo, e eles também tinham total acesso a ao nosso repositório de fontes, podendo ver a qualquer hora como estava o projeto. A gestão dos requisitos era feita sempre em conjunto e sempre que uma tarefa ou história parava ou era concluída eles poderiam ver, e também interagir. Mantivemos 100% de transparência em todos os momentos, mesmo nos momentos em que tivemos problemas. O time da Level Up! depois disse que ficou satisfeito com a transparência e gostaram da evolução do projeto e do processo.

Fizemos releases internas frequentes, onde o time da Level Up! avaliava a evolução do produto e nos fornecia feedback, sempre incorporadas de volta ao produto.

Sempre trabalhamos com metas de prazo e custo. O projeto como um todo ficou um pouco acima da estimativa inicial, mas isso já estava claro que provavelmente aconteceria antes da metade do projeto. As estimativas ainda assim sempre foram totalmente transparentes, e chegamos a estimar desde funcionalidades grandes até pequenos acertos de poucas horas. Foi apreciada também a transparência no entendimento das variações, o que ajudou a deixar todos tranquilos sobre a real evolução do projeto.

A documentação foi toda baseada no wiki do projeto, leve e simples. Com o uso do BDD boa parte da documentação acabou ficando desnecessária já que a escrita com Gherkin facilita o entendimento até por usuários de negócio.

A Lambda3 mantém seu processo de integração contínua, com troca constante de código e build automatizado, e o Level Up! também faz o build automatizado. Há algum tempo eles passaram a puxar nossas mudanças, e fazendo o release a partir do seu próprio servidor de build, uma evolução com o modelo inicial que era baseado em builds na Lambda3 disponibilizadas à Level Up!.

Status atual e futuro

O projeto continua em andamento. Estamos em processo de refatoração para baixar a complexidade decorrente da entropia natural e poder continuar evoluindo. Ainda que o código tenha evoluído de forma ordenada e refatoração sempre fosse parte do processo é esperado que esse tipo de coisa aconteça. Novas features estão sendo acrescentadas e o produto segue evoluindo, assim como o processo. Nossos clientes estão bastante satisfeitos e seguem nos dando feedback sobre o que esperam, e nós continuamos com 100% de transparência.

É um projeto sem dor de cabeça, sem viradas de noite, sem cliente insatisfeito gritando com o fornecedor, sem orçamentos estourados, prazos e oportunidades perdidos. Os desenvolvedores trabalham de casa, da empresa, da praia, a hora que querem, sempre respeitando os compromissos assumidos com o cliente. O projeto não tem gerentes de nenhuma forma, seja de projeto ou funcional, e é totalmente auto organizado e auto gerido. Resumindo, é um projeto win/win, assim como tem sido todos os projetos de todos os clientes da Lambda3.

Concluindo

Espero que tenha ajudado vocês a terem uma ideia de como é um projeto na Lambda3. Temos mais alguns pra contar, mas ainda vai um tempo antes de eles amadurecerem a ponto de virarem um case. Mas fiquem ligados, porque ainda esse trimestre devemos colocar pelo menos mais um por aqui.

Giovanni Bassi

Arquiteto e desenvolvedor, agilista, escalador, provocador. É fundador e CSA da Lambda3. Programa porque gosta. Acredita que pessoas autogerenciadas funcionam melhor e por acreditar que heterarquia é mais eficiente que hierarquia. Foi reconhecido Microsoft MVP há mais de dez anos, dos mais de vinte que atua no mercado. Já palestrou sobre .NET, Rust, microsserviços, JavaScript, TypeScript, Ruby, Node.js, Frontend e Backend, Agile, etc, no Brasil, e no exterior. Liderou grupos de usuários em assuntos como arquitetura de software, Docker, e .NET.