Article image
Arthur Rossini
Arthur Rossini06/10/2026 17:57
Compartilhe

O desafio logístico fora dos grandes centros: Construindo uma aplicação de rotas do zero

    Você já teve aquele amigo que soltava: "Eu moro na esquina do bar do seu José, aqui perto da parada de carro..."?

    Em regiões fora das grandes capitais e áreas metropolitanas, essa falta de padronização é uma realidade constante. E quando falamos de logística, entregas de pacotes e otimização de rotas, essa informalidade nos endereços transforma-se num problema complexo de engenharia.

    Tive a ideia deste projeto ao conversar com um colega que faz entregas na nossa região. Ele comentou comigo que o processo de organizar os pacotes, agrupar as áreas e definir por onde começar a rota era uma verdadeira bagunça, feita muitas vezes com base na memória e na intuição. Pensei comigo: "E se eu montar uma aplicação para, ao menos, separar, roteirizar e setorizar estes pacotes?".

    Após realizar um levantamento de requisitos operacionais (briefing) sobre o processo atual dele, percebi que o desenvolvimento de um sistema não precisaria ser algo puramente abstrato. Havia um problema real e tangível a ser resolvido.

    Sou estudante de Engenharia de Software e, através da minha jornada acadêmica em ensino à distância e das minhas experiências no suporte técnico de sistemas, tenho procurado aplicar os conceitos teóricos na resolução de atritos do dia a dia. A vida de um programador é dar a cara a tapa, tentar, errar e iterar. Por isso, decidi abraçar este desafio logístico.

    Montei a arquitetura base para o sistema. Grande parte das tecnologias que planeio utilizar envolve conceitos com os quais ainda não tive um contacto tão profundo, mas estou a utilizar este projeto para adquirir horas de extensão universitária e como uma fundação robusta para um possível Trabalho de Conclusão de Curso (TCC). Sem esquecer, claro, a perspetiva de monetizar a ferramenta no futuro, visto que o meu colega será o beta tester e o primeiro utilizador real da plataforma.

    Boas práticas: Planeamento antes da primeira linha de código

    No ecossistema de desenvolvimento, existe uma pressa enorme para começar a escrever código. No entanto, se estudamos boas práticas de engenharia, como os princípios SOLID e padrões de arquitetura, por que não aplicá-los antes de sujar as mãos? Até ao momento, planejei toda a estrutura "no papel".

    Primeiro, desenhei o Diagrama de Atividades, mapeando detalhadamente o fluxo do entregador — desde a autenticação na tela inicial até à verificação em loop de pacotes pendentes e à ação contínua de fotografar a etiqueta. Quando o entregador inicia a jornada, ele passa pela extração de dados através de inteligência artificial (Gemini), pelo cálculo do setor e pela gravação do pacote nas rotas pendentes. Este fluxo garante que o utilizador não precise de interagir dezenas de vezes com a tela do celular enquanto está na rua; o ciclo pergunta sistematicamente se existe "Cadastro de mais Pacotes?" antes de prosseguir.

    image

    Mas o verdadeiro cérebro da aplicação reside em como os dados são estruturados e como as entidades interagem entre si no backend. Para isso, construí um Diagrama de Classes e Entidade-Relacionamento detalhado.

    Dissecando a Arquitetura: O Diagrama de Classes

    Para que a aplicação seja resiliente a endereços ambíguos, a modelagem de dados precisa de ser extremamente flexível e, ao mesmo tempo, tipada. O diagrama que estruturei isola a lógica de negócio das integrações externas, utilizando conceitos avançados de Programação Orientada a Objetos.

    image

    1. O Domínio de Utilizador e Pacote

    A base de controle do sistema passa por garantir que cada utilizador tenha um acesso seguro e um registo de atividade claro. No diagrama, a classe Usuario é responsável pela autenticação, contendo propriedades essenciais como id, login, senha_hash (garantindo que a palavra-passe nunca seja armazenada em texto limpo) e um identificador booleano ativo. Os métodos AutenticarSenhaDigitada(String) e DesativarAcesso() geram o ciclo de vida deste utilizador.

    A relação de cardinalidade estipula que um Usuario pode ter de zero a muitos objetos da classe Pacote associados (1 para 0..*). A classe Pacote atua como o núcleo operacional da entrega, registrando o RuaLida, NumeroLido, o status (se está pendente ou entregue) e um campo fundamental para métricas de desempenho: o TempoProcessamentoMS. Este último permitirá medir quanto tempo a inteligência artificial demora a extrair os dados, ajudando a otimizar a experiência do utilizador. As ações do pacote são controladas pelos métodos GravarComoPendente() e RegistrarBaixa().

    2. Modelagem Geográfica: Cidades e Setores

    A abstração geográfica foi desenhada para escalar. A classe Cidade contém o Nome, o CepGeral e uma propriedade chamada ModuloEstrategia, gerindo o comportamento através do método BuscarSetores(). Uma cidade possui múltiplos Setores (1 para 1..*).

    A classe Setor é aquilo que o entregador vai realmente ver na sua tela. Para otimizar o interface visual e a usabilidade (UX), inclui atributos como CodigoCurto (ex: "ZN" para Zona Norte), CorHex (para pintar o pacote visualmente na aplicação com cores específicas, facilitando a identificação rápida) e NomeExibicao. O método GerarPacoteVisual() retorna um dicionário para montar o interface no lado cliente. Múltiplos pacotes (0..*) são alocados num único Setor (1).

    3. O Motor de Regras: Resolvendo os Endereços Caóticos

    Aqui entra a solução de engenharia para o problema do "bar do seu José". Um setor é composto por várias instâncias da classe RegraRua (1 para 1..*).

    Em vez de depender estritamente de nomes oficiais, a classe RegraRua possui o campo NomeRuaLimpo e, de forma muito inteligente, uma lista estendida chamada Apelidos (List<String>). Isto significa que o sistema pode validar se o endereço extraído é a "Avenida Principal", a "Rua da Igreja" ou o "Largo do Mercado". Além disso, possui NumeroInicio e NumeroFim, permitindo que ruas muito longas sejam divididas em setores diferentes, dependendo do bloco de numeração. O atributo LadoVia ajuda a evitar que o entregador precise de atravessar rodovias movimentadas de forma ineficiente. Estes dados são validados internamente pelos métodos ContemNumero(Numero: int) e ValidarLado(Numero: int).

    4. Integração com Inteligência Artificial e Padrões de Projeto

    Para efetuar a leitura das etiquetas de transporte, que muitas vezes vêm com formatação danificada ou caligrafia difícil, criei o ExtratorGeminiService. Este serviço guarda a apiKey e a ModeloVersao, contendo o método central ProcessarImagem(foto: Base64). A imagem capturada pelo celular é convertida em base64 e enviada para a API.

    Para proteger a minha camada de domínio de possíveis alterações na resposta da inteligência artificial, implementei o padrão DTO (Data Transfer Object). O serviço do Gemini não devolve uma entidade complexa, mas sim um objeto simples: EnderecoDTO, que contém atributos básicos como rua, numero, bairro e cep.

    5. Inversão de Dependências e Cálculo

    Por fim, o DTO transita para o motor de lógica através da interface ICalculadoraSetor, que expõe o contrato DefinirSetor(Endereco: EnderecoDTO, RegrasCidade: List<RegraRua>) retornando um Setor definitivo. Este contrato é implementado concretamente pela classe CalculadoraRuaNumero, que também detém o método HigienizarNomeRua(Texto: String) para limpar ruídos e padronizar o texto antes de comparar com a nossa base de regras. Esta injeção de dependência torna o código facilmente testável (através de mocks) e sustentável a longo prazo.

    Os grandes desafios do projeto a longo prazo

    Com toda esta arquitetura delineada, tenho clareza sobre os próximos obstáculos:

    Mapeamento Prévio: Alimentar a base de dados do PostgreSQL com as entidades RegraRua da cidade. É um trabalho manual considerável no início, mas como a cidade é pequena, o esforço compensa amplamente ao eliminar a dependência e os custos de APIs de geolocalização pagas.

    Segurança e Privacidade (LGPD): Garantir a anonimização e segurança dos dados pessoais extraídos das etiquetas, assegurando que o EnderecoDTO transite de forma segura.

    A Stack Tecnológica Central: Planeio codificar o backend inteiramente em Python, aproveitando o ecossistema robusto desta linguagem para o manuseamento de dados e consumo da API do Gemini. O armazenamento será relacional através do PostgreSQL, ideal para manter a integridade destas associações complexas.

    O Salto para o Mobile: Como mencionei anteriormente, a vida é dar a cara a tapa. Desenvolver a aplicação móvel (o cliente que irá gerar os pacotes visuais a partir da CorHex do setor) será a minha maior curva de aprendizagem, exigindo aprofundamento em frameworks de interface de utilizador móvel.

    Criar soluções locais para cenários onde o padrão das grandes infraestruturas tecnológicas falha é o que torna o desenvolvimento de software uma disciplina verdadeiramente intrigante. Transformar caos logístico em entidades estruturadas num diagrama de classes é o primeiro passo para uma verdadeira transformação digital.

    E você, também costuma planejar extensivamente as suas classes e diagramas de atividades antes de abrir o editor de código? Está a planear algo novo ou partindo para cima de algum projeto desafiante?

    Compartilhe
    Comentários (0)