Trabalho Extra: Implementação em Go (Golang)
Este documento descreve o Trabalho Extra Opcional da disciplina: reimplementar o Sistema de Recomendação Colaborativo em Go (Golang).
Esta implementação é opcional e vale +5 pontos extras na nota final da disciplina.
Ela deve ser entregue individualmente e avaliada separadamente do TP1.
Por que fazer este trabalho?
1. Go é diferente de tudo que você já viu
Você já explorou três paradigmas no TP1:
- Java — Orientado a Objetos, com herança, classes e exceções.
- Prolog — Declarativo, baseado em fatos e regras lógicas.
- Lisp/Racket — Funcional, com imutabilidade e funções de alta ordem.
Go não é nenhum dos três. É uma linguagem moderna, compilada e de tipagem estática que propositalmente rejeita a herança clássica e substitui threads por um modelo de concorrência próprio. Para uma disciplina de Conceitos de Linguagens de Programação, esse contraste é exatamente o ponto.
2. Concorrência como primitiva da linguagem
Esta é a principal razão para fazer este trabalho. As duas linguagens resolvem o problema de concorrência de formas filosoficamente opostas.
O modelo de Java: Threads do Sistema Operacional
Em Java, concorrência é feita com threads gerenciadas pelo SO. Cada thread tem uma pilha própria (~1 MB), e a comunicação entre elas é feita via memória compartilhada — o que exige mecanismos de proteção explícitos:
// Java — executar tarefas em paralelo
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int candidatoId : candidatos) {
final int cid = candidatoId;
executor.submit(() -> {
if (ehVizinho(uid, cid)) {
synchronized (vizinhos) { // ← proteção obrigatória
vizinhos.add(cid);
}
}
});
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);O problema deste modelo: estado compartilhado é perigoso. Esquecer um synchronized causa race conditions difíceis de reproduzir e depurar. Java oferece volatile, AtomicInteger, ConcurrentHashMap para mitigar isso — mas a complexidade cresce rapidamente.
O modelo de Go: Goroutines + Channels
Go adota uma filosofia diferente, resumida no seu slogan oficial:
“Do not communicate by sharing memory; instead, share memory by communicating.”
Em vez de threads que brigam por acesso a variáveis compartilhadas, Go usa goroutines (muito mais leves que threads — custos na casa de ~2 KB) que se comunicam passando mensagens por channels:
// Go — executar as mesmas tarefas em paralelo
ch := make(chan int, len(candidatos)) // ← channel tipado
for _, cid := range candidatos {
go func(candidatoID int) { // ← goroutine: palavra-chave "go"
if ehVizinho(uid, candidatoID) {
ch <- candidatoID // ← enviar resultado pelo channel
} else {
ch <- -1
}
}(cid)
}
for range candidatos {
if id := <-ch; id != -1 { // ← receber do channel
vizinhos = append(vizinhos, id)
}
}Não há synchronized, não há Lock, não há memória compartilhada. O channel é o ponto de sincronização.
Comparação direta
| Aspecto | Java (Threads) | Go (Goroutines) |
|---|---|---|
| Custo por unidade | ~1 MB (pilha do SO) | ~2 KB (gerenciada pelo runtime) |
| Sincronização | synchronized, Lock, volatile |
Channels (chan) |
| Comunicação | Memória compartilhada | Passagem de mensagens |
| Modelo teórico | Monitor / Semáforos | CSP (Communicating Sequential Processes) |
| Quantidade prática | Centenas | Milhões |
A busca de vizinhos da Fase 3 é um caso ideal: para cada usuário candidato, você pode lançar uma goroutine independente que avalia a vizinhança e envia o resultado por um channel. Não há estado compartilhado — cada goroutine só lê os dados (imutáveis) e escreve no seu próprio resultado.
Compare isso com a versão Java que você já implementou: quantas linhas a mais foram necessárias para garantir thread-safety?
3. OO sem herança — é possível?
Go tem structs e interfaces, mas sem herança. Toda composição é feita de outra forma. Reimplementar o mesmo problema que você modelou em Java com classes e hierarquias, agora sem elas, é um exercício valioso de design de software.
4. O juiz online já está pronto
Go lê de stdin exatamente como Java. Os mesmos problemas do juiz online valem para Go. Não há problema novo para aprender — só a linguagem muda.
O que será avaliado
A entrega tem dois componentes:
1. Código funcional
- Implementação das três fases (Consultas, Regras de Negócio, Recomendação Colaborativa).
- Suporte aos três tipos de recomendação:
RESTRITO,TOLERANTEeESPECIALIDADE. - Uso obrigatório de goroutines na busca de vizinhos (Fase 3).
- Leitura via
os.Stdin(compatível com o juiz online).
2. Relatório comparativo (mínimo 1 página)
Responda com base na sua experiência de implementação:
- O código em Go ficou mais ou menos legível que o Java para este problema? Por quê?
- Em quais situações as goroutines trouxeram ganho real? Quando não trouxeram?
- Como a ausência de herança impactou a modelagem do problema?
- Compare o tratamento de erros em Go (
val, err) com exceções em Java (try/catch).
Como começar
Go é uma linguagem minimalista e com instalação simples:
- 📥 Download: go.dev/dl — disponível para Windows, Mac e Linux.
- 📖 Tour oficial: tour.golang.org — introdução interativa em ~2 horas.
- 🔧 Nenhuma IDE necessária — um editor de texto e o terminal bastam.
Antes de começar a implementar, leia os capítulos do Tour oficial sobre:
- Structs e Métodos — equivalente às classes de Java.
- Goroutines e Channels — o coração do diferencial de Go.
- Interfaces — polimorfismo sem herança.
Submissão
- Submeta o código no mesmo juiz online utilizado para Java (formato de entrada e saída idêntico).
- Entregue o relatório comparativo no formato PDF junto com o link da submissão.
- Prazo: 10 de junho de 2026.