Projetos que todo programador deveria enfrentar (2019)
(austinhenley.com)- Se for difícil escolher um side project, projetos como editor de texto, jogo 2D, compilador e mini sistema operacional são bons pontos de partida, porque quanto mais vezes você os constrói, maior é a amplitude do aprendizado
- O editor de texto leva você a implementar por conta própria a estrutura de armazenamento do documento, o comportamento do cursor, desfazer/refazer e quebra de linha, aprendendo estruturas de dados e abstração
- Até um jogo 2D simples como Space Invaders revela a estrutura básica da programação de jogos, incluindo desenho na tela, tratamento de entrada, game loop, gerenciamento de estado de objetos, IA dos inimigos, som, shaders e rede
- O compilador Tiny BASIC e o mini sistema operacional fazem você lidar diretamente com conceitos de baixo nível, como lexing, parsing, análise semântica e geração de código, ou compilação cruzada, bootloading, gerenciamento de memória e escalonamento
- Planilhas e emuladores de console combinam a dificuldade dos projetos anteriores e evoluem até a etapa de criar até mesmo uma máquina virtual que imita o funcionamento real
Projetos que valem a pena criar repetidamente
- Quando você precisa de um side project ou quer aprender uma nova linguagem de programação ou framework, fazer o mesmo projeto várias vezes ainda pode ensinar algo diferente a cada tentativa
- Os projetos recomendados variam em dificuldade e área de aprendizado
- Editor de texto: estruturas de dados, comportamento do cursor, desfazer/refazer, representação em tela
- Jogo 2D: desenho na tela, tratamento de entrada, game loop, objetos e gerenciamento de estado
- Compilador: lexing, parsing, análise semântica, geração de código
- Mini sistema operacional: boot, gerenciamento de memória, escalonamento, sistema de arquivos
- Planilhas e emuladores de console: combinam os conceitos dos projetos anteriores em uma estrutura maior
Editor de texto
- O editor de texto é uma ferramenta usada todos os dias, mas se você o implementar diretamente sem usar um componente básico de caixa de texto, terá que lidar com os detalhes de movimento do cursor, seleção, inserção e exclusão
- O maior desafio é como armazenar o documento de texto na memória
- Um array simples tem desempenho ruim ao inserir texto em posições que não sejam o fim do documento
- Estruturas para comparar incluem array, rope, gap buffer e piece table
- O cursor não se move apenas para cima e para baixo
- Ao ir para uma linha curta, ele vai para a posição possível e, quando depois encontra uma linha longa o suficiente, tenta voltar para a coluna original, um comportamento de memória de coluna
- Depois do editor básico, você pode adicionar desfazer/refazer e quebra de linha
- Materiais de referência
Jogo 2D - Space Invaders
- Mesmo um jogo simples exige estruturas de dados e padrões de projeto próprios
- Em vez de um grande engine de jogos, usar uma biblioteca básica de gráficos 2D como SDL, SFML ou PyGame evita que as partes mais interessantes fiquem escondidas
- O jogo cria o efeito de movimento apagando a tela e redesenhando rapidamente cada elemento
- O fluxo real segue uma estrutura que repete desenho, recebimento de entrada do usuário e processamento da lógica do jogo dentro de um game loop
- O tratamento de entrada precisa considerar detalhes como primeiro pressionamento de tecla ou botão do mouse, manter pressionado, soltar e duplo clique
- Se você ficar apenas verificando a entrada, o restante do jogo fica parado
- O gerenciamento de objetos e estado do jogo também precisa ser tratado diretamente
- O padrão factory pattern ajuda a criar inimigos que aumentam dinamicamente
- É possível aplicar uma máquina de estados à IA dos inimigos
- Depois do jogo básico, é possível adicionar menu de título, tela de game over, execução na mesma velocidade em computadores diferentes e uma IA inimiga mais interessante
- Indo além, você pode implementar efeitos de shader, som e até multiplayer online
- Materiais de referência
Compilador - Tiny BASIC
- Um compilador é um projeto de criar uma ferramenta que permite que outras pessoas construam ainda mais coisas
- Tendo como alvo uma linguagem pequena da família BASIC, Tiny BASIC, você pode escrever do zero um compilador que gere saída em outra linguagem que conheça bem
- Por exemplo, pode criar um compilador de Tiny BASIC em Python que gere código C#
- Se não gerar assembly nem C, você consegue focar mais no próprio compilador
- O fluxo de implementação acompanha passo a passo o processo de tratamento de linguagem
- lexical analysis, que divide o código de entrada em tokens
- syntactic analysis, que verifica a estrutura da entrada e cria uma representação em árvore
- recursive descent parsing
- abstract syntax tree
- semantic analysis, que verifica se o código faz sentido semanticamente e segue as regras de tipos
- optimization passes
- code generation
- Um compilador simples pode ser concluído em poucos dias e, depois disso, você pode adicionar biblioteca padrão, passes de otimização e mensagens de erro melhores
- No PeayBASIC, uma funcionalidade simples de gráficos 2D foi adicionada à biblioteca padrão
- Materiais de referência
Mini sistema operacional
- Os algoritmos e estruturas de dados de sistemas operacionais podem parecer abstratos ou inúteis em sala de aula, mas podem ser aplicados também em várias áreas, como jogos ou modelos de previsão do comportamento humano
- Ao implementar um por conta própria, você passa a entender com mais profundidade o que acontece dentro de um sistema operacional
- Por causa da dependência de hardware, há uma barreira inicial e uma curva de aprendizado, mas seguindo livros ou tutoriais é possível criar um OS inicializável capaz de executar programas feitos por você
- Os tópicos de aprendizado são os seguintes
- Cross compiling
- Bootloading
- BIOS interrupts
- modos x86
- gerenciamento de memória e paginação
- Scheduling: por exemplo, round robin
- File systems: por exemplo, FAT
- Materiais de referência
Projetos mais difíceis: planilhas e emuladores de console
- Um aplicativo de planilha, como o Excel, combina os desafios do editor de texto com os do compilador
- É preciso representar o conteúdo das células na memória
- É preciso implementar um interpretador para a linguagem de programação usada nas fórmulas
- Materiais de referência para planilhas
- Um emulador de console de videogame é um projeto que reúne em um só lugar as dificuldades de implementar compiladores, sistemas operacionais e engines de jogo
- Para emular um console real, é preciso escrever uma máquina virtual que se comporte como a CPU e os demais componentes de hardware
- Nessa máquina virtual, é possível executar jogos feitos para aquele console
- Como ponto de partida, recomenda-se emular o CHIP-8, um console virtual mais simples que consoles reais
- Também é possível emular NES, SNES, Gameboy e Gameboy Advance, e há bastante documentação e emuladores open source, mas cada console tem particularidades interessantes
- Certos jogos podem depender de bugs ou funcionalidades não documentadas de hardwares específicos
- O PICO-8 se tornou um console “fantasy” lucrativo
- Materiais de referência para emuladores
Projetos adicionais sugeridos
- Ideias extras de projetos foram reunidas do Hacker News, Reddit, Twitter e email
- banco de dados feito do zero
- ray tracer
- clone do MS Paint
- editor de gráficos vetoriais
- decodificador de imagens
- aplicativo web de sala de chat
- calculadora de dígitos de pi
- utilitário geral de terminal como o grep
- cliente e servidor FTP
1 comentários
Opiniões no Hacker News
Criar um editor de texto, um compilador, um sistema operacional ou um ray tracer pode fazer de você um programador melhor, mas não necessariamente um engenheiro de software melhor
Pelo contrário, pode até piorar suas habilidades de engenharia de software ao internalizar a doutrina desastrosa do “Not Invented Here”
Hackers ficam obcecados por teoria avançada, como Big O, estruturas de dados e HoTT, mas quase não se discute nem se pratica o que é essencial na engenharia de verdade: “decidir o que fazer por conta própria e quando usar uma biblioteca”, “identificar boas bibliotecas e frameworks”, “julgar onde vale a pena otimizar”, “escrever código que continue legível daqui a alguns anos” e “enxergar o projeto como um grande sistema complexo, incluindo dependências de software e não software”
Por isso, proponho um mecanismo de busca na web como projeto alternativo. Algoritmos de correspondência de strings e afins já foram feitos por outras pessoas, então não se preocupe com isso; no começo, mesmo que ele só dê suporte a uma parte da web e a 1 usuário simultâneo, basta “simplesmente” criar um mecanismo de busca e um crawler que funcionem de verdade
Um editor de texto, um compilador, um sistema operacional ou um ray tracer também podem treinar exatamente todas essas atividades
Falando como alguém que já trabalhou em um ray tracer usado em vários longas-metragens, todos os itens citados acima também se aplicaram àquele projeto
No fim, a diferença parece estar mais entre fazer algo pequeno e divertido ou aplicar as mesmas restrições destruidoras de alma de um trabalho corporativo pago e remover toda a diversão
Primeiro, esses blocos prontos, em geral, são muito mais frequentemente ruins; como resultado, o software também reflete essa ruindade, e a vida deixa de ser usar software para virar manter e apaziguar essas coisas ruins
Segundo, mesmo que os blocos sejam de boa qualidade, eles limitam os tipos de software que você pode usar. O ideal é imaginar o comportamento desejado, escrever software para fazê-lo e, nesse processo, criar os blocos
Se você usar apenas blocos prontos, uma boa parte dos softwares excelentes nem poderá ser criada, e acredito que esse também seja o motivo de não haver tantos softwares excelentes ao nosso redor
Se você estiver criando “um software quase igual ao que sempre vimos”, o segundo problema se aplica menos, e o primeiro talvez seja administrável porque você usa principalmente o caminho feliz. Mas esse tipo de software logo será usado por IA, não por pessoas
Essas habilidades também são importantes, mas em algum momento é preciso desenvolver a base, e tornar-se um programador melhor certamente ajuda em todo o conjunto de habilidades listado acima
Pessoalmente, engenharia de software é o que faço para pagar as contas, enquanto programação foi algo que comecei porque era divertido
Os projetos deste texto são do tipo que eu gostaria de fazer por diversão, se tivesse tempo
Do ponto de vista de UI/Web, além de uma planilha, que é muito útil para entender sistemas de fluxo de dados, eu recomendaria estes itens
Criar um videogame simples em Unity ou Unreal ajuda a entender restrições de desempenho em jogos, onde 30~60 fps são importantes, e também ajuda a criar interfaces rápidas em outros lugares, inclusive na web
Criar um framework JavaScript simples parecido com React ajuda a entender fluxo de dados e tratamento de eventos
Criar sua própria biblioteca HTTP que encapsule XMLHTTPRequest faz você entender desde o início como enviar e ler requisições HTTP, mesmo que hoje exista fetch, o que ajuda depois na depuração de problemas de CORS ou de requisições OPTIONS
Isso também foi discutido na época
Challenging projects every programmer should try - https://news.ycombinator.com/item?id=21790779 - dez. de 2019 (297 comentários)
Há também um texto relacionado
More challenging projects every programmer should try - https://news.ycombinator.com/item?id=25489879 - dez. de 2020 (223 comentários)
+1 para um mini sistema operacional
Desenvolvedores de aplicações dependem de muitos recursos do sistema operacional, como gerenciamento de memória e sistemas de arquivos, e em algum momento acabam se perguntando: “como essas coisas funcionam por trás?”
Por isso, no meu tempo livre, mexi no xv6(https://github.com/mit-pdos/xv6-public)
Aprender em um livro-texto vários algoritmos de escalonamento de processos é totalmente diferente de implementá-los por conta própria, e aprendi muito
Como desenvolvedor de apps móveis, a chance de esse conhecimento ter relação com meu trabalho é praticamente 0, mas com certeza é divertido
Ter desenvolvido um jogo 2D sem engine foi a experiência mais humilhante que me fez perceber o quanto os computadores ficaram absurdamente rápidos
Mesmo fazendo algo que você tem certeza de que seria lento demais, até no Game Boy há um milhão de operações por segundo, então simplesmente roda. Um milhão era um número maior do que eu imaginava
Você começa pensando: “Espera, você procura e desenha todos os sprites toda vez? Não há nenhum cálculo diferencial esperto que saiba apenas o que precisa mudar, nem um segundo buffer que consulte o frame anterior para reduzir trabalho?”; aí fica ainda mais surpreso ao ver jogos muito mais complexos que de fato passaram a usar essas técnicas
Por exemplo, um atlas de sprites é uma forma típica de usar esse tipo de estrutura de dados. Como não há motivo para enviar vários sprites que normalmente são renderizados de uma forma previsível a cada vez, basta enviar uma imagem grande e amostrar partes dela
Pelos padrões de hoje, isso está certo. Hardware comercial de entrada, mesmo que nem seja um PC gamer, consegue lidar com quase tudo de uns 15 anos atrás com renderização burra do tipo desenhar a cena e redesenhar
Como era só hardware puro e assembly, era preciso fazer tudo manualmente: gráficos, som, entrada, gerenciamento de memória etc.
Acho que uma introdução ideal seria um ambiente simplificado em que um programador iniciante pudesse lidar com tudo isso e criar um jogo 2D, mas sem o peso excessivo necessário para fazê-lo funcionar
Se você acha que precisa do padrão Factory para criar Space Invaders, há algo errado
Acho muito improvável que o original tivesse esse tipo de conceito de design
Quando o cérebro é infectado por isso, ele começa a procurar maneiras de espalhar a infecção
Será que lemos textos diferentes?
Tenho vontade de fazer algo muito mais físico, como simulações precisas de dinâmica de voo de robôs, drones autopilotados ou espaçonaves com parâmetros GNC programáveis
Tenho o “Fundamentals of Astrodynamics”, de Bate, Mueller e outros, e queria fazer alguma coisa nesta temporada de férias
Falo de simulação porque o resto parece caro demais. Tenho muito interesse no lado GNC de robôs, e adoraria recomendações de bons materiais
Algo como um Segway que consiga ficar parado no lugar sem cair ou sair voando da mesa
Imagino que você precisaria de um microcontrolador, uma IMU, controladores de motor de passo, motores, rodas de LEGO e talvez um pedaço de madeira
Não fiz isso pessoalmente, então minhas suposições podem estar bem erradas
Gostaria de ouvir mais sobre o conteúdo do livro e que tipos de projetos poderiam ser feitos com ele
Depois de lidar com software o dia inteiro, é muito bom trabalhar voltado a um objeto físico
Acho que um pequeno ray tracer de brinquedo também é um ótimo exercício para tentar
Basta lidar com esferas e algumas fontes de luz, reflexão difusa e especular, e gerar gráficos em bitmap
Se você não deixar crescer demais, pode ser um projeto com escopo relativamente bem delimitado
Quando você tenta renderizar gráficos, aprende muito sobre o quanto pode abusar da geometria e das estruturas de dados
https://austinhenley.com/blog/morechallengingprojects.html
https://raytracing.github.io/
https://raytracing-iow.shuttleapp.rs
É uma lista interessante e, embora dependa da inclinação e da situação de cada pessoa, é um bom ponto de partida se você está procurando ideias
Eu não diria que todo programador precisa tentar alguma coisa específica; vou apenas listar o que eu escolhi fazer pessoalmente
No Sinclair ZX Spectrum, fiz editores e trackers de pauta musical muito rudimentares, e, como jogo 2D, fiz um Space Invaders com apenas um invasor
Aquele computador nem era meu. No meu primeiro computador, um 386, fiz um compactador Huffman, um índice B-Tree que era mais rápido que DBase/Clipper, um gerador de formulários orientado a objetos e vários programas de fundo para DOS, um dos quais acabou sendo usado depois no processo de instalação de uma grande empresa
Alguns anos depois, fiz um verificador de e-mail para dial-up, um parser manual para destaque de sintaxe e até algo parecido com uma planilha, e continuo fazendo isso até hoje. Com certeza devo ter deixado algo de fora
Uma boa lista. Seria ótimo mantê-la como uma lista viva, para que possa evoluir junto com o tempo
Eu gostaria de acrescentar duas coisas
Criar um memcached leve exige uma mistura de algoritmos fundamentais e boas práticas de design de sistemas. É um problema “simples”, mas exige pensar bem por vários ângulos, como invalidação, concorrência e gerenciamento de memória
Também é uma boa ideia criar o seu próprio Docker. Não é tão complicado quanto parece e oferece a oportunidade de entender os fundamentos da programação de sistemas operacionais, algo que engenheiros hoje em dia não usam muito no trabalho cotidiano