Quando falamos em desenvolvimento de software, muitas pessoas ainda caem na armadilha de discutir "qual linguagem é melhor?". A verdade é que bons Desenvolvedores não se preocupam com a linguagem A ou B. O que importa é resolver o problema de forma eficiente, tirando o proveito do que cada linguagem oferece de melhor.
Neste post, vou contar a trajetória do desenvolvimento de um app de legibilidade (readability app), construído unindo Rust, C++ e Go -- cada um cumprindo um papel específico -- e mostrar como, no fim das contas, tudo se integra através de bibliotecas compartilhadas no nível mais baixo possível: o binário.
O Problema
O objetivo era criar um aplicativo desktop capaz de:
- Calcular o Flesch Reading Ease Score de um texto.
- Gerar Insights Inteligentes com base no TF-IDF + Similariade de cosseno.
- Ter uma interface amigável para o usuário final.
A Arquitetura Multilíngue
E com cada linguagem cumprindo seu papel.
Rust surgiu como (core library) por conta da sua excelênte performace e segurança para o cálculo do Flesch Reading Ease Score e métricas de texto. Já o C++... na verdade o C++ apareceu como um "intruso", poderia muito bem ter realizar o trabalho dele simplesmente com Rust, mas como já estava nessa pegada de multilinguagem resolvi acrescenta-lo ao projeto. Então o papel do C++ foi realizar a implementação do motor de TF-IDF e o cálculo de similaridade de cosseno para gerar insights dinâmicos através da técnica de (NLP embedding).
O Go por lado disponibiliza a interface desktop que foi desenvolvida utilizando a lib Fyne para melhor interação do usuário, além de servir de ponto entre Rust e C++ via cgo.
As integrações são feitas utilizando C (ponte), através de ABI simples para expor as funções Rust e C++ em formatos shared library (.so).
O Resultado final? Um único binario Go que linka dinamicamente contra libreadability.so (Rust) e libtextembedder.so (C++).
Diagrama do fluxo Go → cgo → PLT → lib.so
+------------------+
| App Go / GUI |
| (chama C wrappers) |
+--------+---------+
|
| via cgo / import "C"
v
+------------------+
| Wrappers C / Go |
| (funções “extern C”) |
+--------+---------+
|
| chamadas indiretas
v
+------------------+
| PLT / GOT (Dynamic Linker) |
+--------+---------+
|
| salto para função externa
v
+-------------------+ +------------------+
| libreadability.so | | libtext_embedder.so |
| (Rust) | | (C++) |
+-------------------+ +------------------+
Explicação do fluxo
-
App Go
Na camada de Interface (Fyne GUI), as funções são invocadas via declaraçãocgo.// #cgo LDFLAGS: -lreadability -ltext_embedder // extern double flesch_score(...); import "C" -
Wrappers C/Go (extern C).
As funções declaradas comextern C, são a "porta de entrada" para as bibliotecas nativas. Fazendo a ponte entre o mundo Go e as libs.so. -
PLT/GOT - Procedure Linkage Table / Global Offset Table.
Quando a chamada aflesch_score(....)é feita, o binário Go não sabe onde essa função estar, então ele vai para PLT que é um trampolim. A PLT redireciona a execução via GOT para o endereço real da função na biblioteca compartilhada.
Isso é o mecanismo derelocação dinâmicaem tempo de execução. -
Bibliotecas compartilhadas (.so).
libreadability.so(Implementada em Rust) contém a lógica de cálculo de legibilidade, elibtext_embedder.so(em C++) contém o mecanismo de TF-IDF + similaridade.
A PLT/GOT resolve os símbolos em tempo de execução e pula para o código correto nessas libs.
Ligação de Baixo Nível
Quando compilamos o App Go, ele não "sabe" calcular legibilidade ou embeddings. Ele apenas chama funções expostas pelas libs compiladas em Rust e C++.
Se inspecionarmos o bínario, vemos exatamente como essa ligação é feita:
$ readelf -d app
Saída (trecho relevante)
NEEDED Shared library: [libreadability.so]
NEEDED Shared library: [libtext_embedder.so]
Ou seja, o app Go depende diretamente dessas bibliotecas compartilhadas.
E mais: com objump, conseguimos rastrear os symbols e ver como o Go chama as funções Rust/C++:
$ objdump -d app | grep flesch_score
Saída:
0000000000405c80 <flesch_score@plt>:
jmp *0xea99a2(%rip) # 12af628 <flesch_score@Base>
Aqui, O Go está pulando para a Procedure Linkage Table (PLT), que é o mecanismo de baixo nível usado para resolver as chamadas a funções externas em bibliotecas dinâmicas.
No caso, fleschscore está vindo diretamente da lib Rust compilada em .so.
E Para o C++:
$ objdump -d app | grep text_embedder
Saída:
0000000000405cf0 <init_text_embedder@plt>:
jmp *0xea996a(%rip) # 12af660 <init_text_embedder@Base>
Mesma lógica, o Go não implementa nada disso, ele apenas salta para dentro da biblioteca C++ que contém o motor de embeddings.
E na prática o que isso significa?
O Go so orquestra, ele não processa nada sozinho. Rust e C++ trazem a performace e algoritimos pesados, já o link dinâmico garante que o binário final use diretamente as funções das libs nativas.
Esse é um exemplo clássico de interoperabilidade real entre linguagens: no final, tudo se resolve no nível do ELF (binário linux), via símbolos, tabelas de relocação e chamadas de função.
Lições aprendidas
- Não importa a linguagem, importa a solução.
Bons devs usam a ferramenta certa para cada parte do problema. - Entender o baixo nível faz a diferenção.
Saber interpretar a saída dereadelf,objumpe outros utilitários similares te dá clareza de como o sistema funciona de verdade. - Interoperabilidade é poder.
Unir Rust, C++ e Go num único app mostra que a programação moderna não é sobre isolamento, mas sim sobre integração.
Conclusão
Construir esse app foi mais do que resolver o problema de legibilidade: foi uma prova prática de que o desenvolvedor que entende multiplas camadas de stack -- Do algoritimo até o binário -- tem o poder real nas mãos.
Seja Rust, C++, Go ou qualquer outra linguagem: no final, o que importa é resolver o problema com elegância e eficiência.
Se achou interessante esse post, e gostou do que foi apresentado. Pode acompanhar a playlist que fiz no Youtube mostrando como esse app foi desenvolvido, ou até mesmo analisar todo o código fonte no GitHub.
Links
- Repositório no GitHub: JuniorPaula/flesch_score_app
- Playlist no YouTube: Playlist Flesch Score App