Ao longo da minha trajetória profissional atuando com banco de dados, infraestrutura, desenvolvimento de soluções corporativas e gestão de projetos, aprendi que muitos projetos de tecnologia não começam a apresentar problemas por causa da linguagem escolhida, do banco de dados adotado ou do framework utilizado. Na maioria das vezes, as dificuldades surgem muito antes, quando uma equipe inicia a construção de uma solução sem estabelecer de maneira clara como cada responsabilidade será distribuída dentro do sistema. É possível utilizar Java, Spring Boot, .NET, Python, Oracle, PostgreSQL, SQL Server ou qualquer outra tecnologia consolidada e, ainda assim, produzir uma solução difícil de manter, testar, evoluir e sustentar. A tecnologia, isoladamente, não corrige uma arquitetura deficiente. Antes de discutir ferramentas, é necessário compreender o problema, definir o domínio, organizar responsabilidades e estabelecer como os diferentes componentes da solução irão se relacionar. Essa é, na prática, uma das bases mais importantes da engenharia de software moderna.
Arquitetura de software pode ser entendida como a estrutura responsável por organizar um sistema, definindo seus principais componentes, as responsabilidades atribuídas a cada um deles e a forma como esses elementos se comunicam. O material que utilizo como referência para esta análise trabalha exatamente com essa concepção: arquitetura não determina, por si só, qual linguagem será utilizada ou qual banco de dados será adotado, mas estabelece como o sistema será organizado e como suas responsabilidades serão distribuídas. Essa distinção é fundamental, principalmente em ambientes corporativos nos quais sistemas permanecem em operação durante muitos anos, recebem novas funcionalidades, passam por mudanças de equipe, sofrem integrações com outras plataformas e precisam responder continuamente a novas necessidades do negócio. Uma arquitetura adequada não serve apenas para permitir que a aplicação funcione no momento da entrega; ela cria condições para que a solução continue sendo compreensível, administrável e sustentável ao longo de todo o seu ciclo de vida.
Costumo comparar esse processo à construção de uma edificação. Antes de iniciar uma obra, ninguém deveria simplesmente comprar materiais, levantar paredes e posteriormente decidir onde estarão os cômodos, instalações elétricas, tubulações ou acessos. Existe uma planta, existe uma definição estrutural e existe uma lógica de organização que antecede a execução física. Com software ocorre exatamente a mesma coisa. Antes de escrever código, criar tabelas ou implementar endpoints, é preciso compreender aquilo que o sistema realmente deverá resolver. O primeiro passo é entender os requisitos do negócio. Em seguida, identificar as entidades existentes naquele domínio, seus atributos, relacionamentos e comportamentos. Depois disso, deve-se organizar as responsabilidades que compõem a solução. Somente quando essas etapas estiverem minimamente compreendidas é que a escolha e a implementação das tecnologias passam a fazer sentido. Em outras palavras, tecnologia deve materializar uma arquitetura previamente compreendida, e não ser utilizada como substituta da própria arquitetura.
Esse raciocínio pode ser sintetizado em um princípio que considero especialmente importante: arquitetura de software não existe para organizar computadores, linguagens ou frameworks; ela existe para organizar responsabilidades. O material de referência reforça exatamente essa visão ao definir arquitetura como a forma de estabelecer os componentes principais de um sistema, suas responsabilidades, a maneira como se comunicam e as regras necessárias para que a aplicação consiga crescer sem se transformar em uma estrutura desorganizada. Na prática, essa organização representa uma forma de reduzir complexidade. Quando cada componente sabe exatamente o que deve fazer e, principalmente, aquilo que não deve fazer, o sistema passa a apresentar fronteiras técnicas mais claras. Essas fronteiras facilitam a manutenção, reduzem dependências desnecessárias e permitem que mudanças sejam realizadas com maior previsibilidade.
Um exemplo bastante simples ajuda a compreender esse conceito. Considere uma funcionalidade de cadastro de usuário ou aluno em determinado sistema. Para quem utiliza a aplicação, a operação pode parecer trivial: preencher informações e clicar em um botão. Internamente, entretanto, diversas responsabilidades precisam ser executadas. O sistema precisa receber os dados enviados, validar campos obrigatórios, conferir determinadas regras, verificar duplicidades, analisar informações como CPF ou e-mail, persistir os dados e, ao final, produzir uma resposta para quem realizou a solicitação. O fluxo apresentado no material segue justamente essa lógica de receber, validar, salvar e responder. Embora todas essas atividades façam parte de um mesmo processo de negócio, elas não representam necessariamente a mesma responsabilidade técnica. Quando esse entendimento não existe, é comum que toda a lógica seja concentrada em uma única função ou classe, criando componentes grandes, fortemente acoplados e cada vez mais difíceis de modificar.
Esse tipo de implementação inicialmente pode transmitir a sensação de velocidade. O desenvolvedor cria uma função, recebe os dados, realiza as validações, acessa diretamente o banco, envia notificações, registra logs e retorna a resposta ao usuário. O problema aparece quando o sistema começa a evoluir. Se uma regra relacionada ao CPF for alterada, aquela função precisa ser modificada. Se o modelo de persistência mudar, novamente a mesma função precisará ser alterada. Se houver modificação no formato da API, novas alterações serão necessárias no mesmo ponto. Com o tempo, aquele componente passa a concentrar responsabilidades demais e pode se transformar em um ponto crítico da aplicação. O próprio material evidencia esse cenário ao mostrar que uma função que recebe dados, valida, persiste, envia informações e responde ao usuário pode se tornar um ponto de dependência excessiva e potencial ponto único de falha. Do ponto de vista técnico, isso aumenta o acoplamento e dificulta testes e manutenção. Do ponto de vista da gestão, aumenta o risco, o esforço das alterações e, consequentemente, o custo do projeto.
É justamente nesse ponto que arquitetura de software deixa de ser apenas uma discussão de desenvolvimento e passa também a ser uma questão de gestão de projetos. Toda decisão arquitetural possui reflexos sobre prazo, orçamento, qualidade, risco, sustentação e capacidade futura de evolução. Um sistema excessivamente acoplado exige mais esforço para qualquer alteração. Uma solução que não possui responsabilidades claramente separadas demanda mais tempo para análise de impacto. Uma aplicação pouco padronizada torna a entrada de novos profissionais mais lenta e aumenta a dependência de pessoas específicas. Ao longo do tempo, essas limitações começam a produzir aquilo que conhecemos como dívida técnica. O problema não é apenas possuir código antigo ou complexo, mas acumular decisões que tornam cada nova mudança mais cara do que a anterior. Por isso, considero que arquitetura também deve ser compreendida como instrumento de governança e gerenciamento de risco tecnológico.
A separação de responsabilidades é um dos mecanismos mais eficientes para controlar esse crescimento da complexidade. Uma classe, módulo ou componente deve possuir uma responsabilidade principal claramente identificável. O elemento responsável por receber uma requisição não deveria concentrar todas as decisões de negócio. Da mesma forma, a camada que implementa regras empresariais não deveria necessariamente conhecer detalhes específicos de persistência. Quem realiza acesso ao banco não deveria decidir se determinado plano comercial pode ser contratado, se uma operação está autorizada ou se determinada regra administrativa foi cumprida. O material de referência destaca justamente essa lógica ao afirmar que componentes diferentes devem exercer funções distintas, evitando que comunicação, validação, persistência e resposta sejam tratadas indiscriminadamente no mesmo local. Essa separação permite que modificações ocorram de forma mais localizada e previsível, reduzindo impactos em cadeia.
Sob a perspectiva de um DBA, esse tema merece atenção ainda maior. Em sistemas corporativos, o banco de dados ocupa uma posição estratégica, porque concentra informações que sustentam processos financeiros, administrativos, fiscais, operacionais e gerenciais. Entretanto, considerar o banco importante não significa transformar toda a lógica da aplicação em responsabilidade do banco. É necessário existir equilíbrio. O banco precisa cumprir adequadamente funções relacionadas à persistência, integridade, consistência, disponibilidade e segurança dos dados, enquanto a aplicação precisa preservar corretamente suas próprias responsabilidades. Quando essa divisão não é respeitada, surgem arquiteturas nas quais parte da lógica está na aplicação, outra parte em procedures, outra em triggers, outra em serviços externos e outra em integrações sem documentação adequada. O resultado é um ambiente de difícil rastreabilidade, no qual pequenas mudanças passam a exigir conhecimento simultâneo de diversos componentes fortemente dependentes entre si.
O material utilizado nesta análise apresenta uma organização inicial baseada em quatro responsabilidades: comunicação, regras de negócio, persistência e banco de dados. A camada de comunicação recebe e devolve informações para quem utiliza o sistema. A camada de regras de negócio concentra as decisões que representam o comportamento da organização. A persistência é responsável por operações como salvar, consultar, atualizar ou excluir informações. O banco de dados, por sua vez, representa o local efetivo de armazenamento dessas informações. Essa estrutura é importante porque permite compreender primeiro o fluxo lógico da aplicação para, somente depois, associá-lo às tecnologias utilizadas. Antes de falar em Controller, Service ou Repository, é muito mais importante compreender por que essas responsabilidades existem.
Quando essa arquitetura é implementada em um ecossistema como Java com Spring Boot, essas responsabilidades começam a receber nomes conhecidos dos desenvolvedores. A comunicação normalmente é representada pelo Controller, responsável por receber requisições HTTP, interpretar informações e encaminhar o processamento para a camada adequada. O material é claro ao demonstrar que o Controller funciona como porta de entrada da aplicação e não deveria ser o local responsável pelas decisões efetivas do negócio. As regras de negócio ficam concentradas no Service, responsável por representar o comportamento e as decisões da aplicação. É nesse ponto que normalmente são executadas validações relacionadas ao funcionamento do negócio, verificações de condições e decisões necessárias ao processamento da solicitação. Já o Repository representa a camada de persistência e estabelece a comunicação necessária com o armazenamento de dados, executando operações de consulta, inclusão, atualização e exclusão.
O fluxo, de maneira simplificada, pode ser entendido como uma solicitação que parte do usuário, passa pelo Controller, segue para o Service, utiliza o Repository quando necessita acessar ou persistir informações e alcança o banco de dados. Depois disso, a resposta percorre o caminho necessário até retornar ao solicitante. O mais importante, contudo, é compreender que Controller, Service e Repository não deveriam existir apenas porque determinado framework utiliza esses nomes. Essas estruturas representam responsabilidades arquiteturais diferentes. Um desenvolvedor pode criar todas essas pastas e, mesmo assim, construir uma aplicação desorganizada caso mantenha regras de negócio dentro de Controllers ou implemente acesso direto ao banco em componentes inadequados. A arquitetura não está no nome do diretório. Ela está na coerência com que as responsabilidades são distribuídas dentro da solução.
Outros componentes também passam a surgir naturalmente conforme a aplicação cresce. O Model, por exemplo, concentra entidades pertencentes ao domínio e representa elementos efetivos do negócio. No exemplo analisado, entidades como aluno, professor, plano, pagamento e treino são elementos que fazem parte daquele contexto específico. Os DTOs, ou Data Transfer Objects, são utilizados para transportar informações entre componentes ou camadas sem necessariamente expor diretamente as estruturas internas das entidades. Configurações podem ser isoladas em componentes específicos, enquanto tratamentos de exceções podem ser centralizados para evitar duplicidade e comportamentos inconsistentes. O material mostra essa organização com estruturas destinadas a Model, Controller, Service, Repository, DTO, Config e Exception, compondo uma base inicial mais previsível para evolução da aplicação.
Uma das conclusões mais importantes desse raciocínio é perceber que a linguagem de programação pode mudar, mas determinadas responsabilidades permanecerão existindo. Hoje uma organização pode utilizar Java e Spring Boot. Amanhã, por decisão tecnológica, financeira ou estratégica, pode adotar outra plataforma. Mesmo assim, continuará sendo necessário receber solicitações, aplicar regras de negócio, consultar e persistir dados, controlar erros e entregar respostas aos usuários ou sistemas consumidores. O material destaca justamente essa independência ao demonstrar que, mesmo que a linguagem seja substituída, a organização fundamental das responsabilidades continuará sendo necessária. Essa percepção é extremamente importante para profissionais que desejam ultrapassar o conhecimento puramente operacional de determinado framework. Tecnologias mudam rapidamente, mas princípios arquiteturais tendem a permanecer relevantes por muito mais tempo.
Essa discussão também possui relação direta com manutenção, disponibilidade e continuidade operacional. Sistemas corporativos raramente permanecem estáticos. Novas regras são incorporadas, integrações são desenvolvidas, relatórios são solicitados, requisitos legais aparecem, bancos de dados crescem e usuários passam a exigir novas funcionalidades. Quanto mais desorganizada estiver a solução original, maior será o esforço necessário para responder a essas mudanças. Uma arquitetura bem definida torna mais simples identificar onde determinada alteração deverá ocorrer, reduz a possibilidade de efeitos colaterais e facilita o trabalho de equipes multidisciplinares. O material ressalta exatamente que uma solução organizada desde o princípio facilita manutenção, evolução, identificação de erros e integração de novos profissionais. Em organizações de grande porte, essa característica deixa de ser apenas conveniente e passa a ser essencial para a continuidade dos serviços.
Na gestão de projetos, costumo considerar arquitetura como parte das decisões que influenciam diretamente a sustentabilidade de uma entrega. Um projeto não deve ser avaliado exclusivamente pela capacidade de cumprir determinado cronograma inicial. Entregar rapidamente uma solução que posteriormente exige alto custo de manutenção pode representar apenas uma transferência de problema para etapas futuras. O verdadeiro desafio é equilibrar prazo, escopo, custo e qualidade sem comprometer a capacidade de evolução. Por isso, discussões arquiteturais precisam ocorrer de maneira proporcional à criticidade e à longevidade da solução. Não significa transformar todo projeto em uma estrutura excessivamente complexa, mas garantir que decisões fundamentais sejam conscientes, documentadas e coerentes com o cenário no qual o sistema deverá operar.
Existe também uma consequência importante para o planejamento de equipes. Em sistemas organizados, novos profissionais conseguem compreender com maior rapidez onde estão as principais responsabilidades e como os componentes se relacionam. Em sistemas desestruturados, grande parte do conhecimento acaba permanecendo apenas com determinadas pessoas. Esse cenário cria dependência operacional e representa um risco significativo para qualquer organização. Uma arquitetura compreensível, acompanhada de documentação adequada, boas práticas de versionamento, padrões de desenvolvimento e gestão técnica consistente, reduz essa dependência individual e transforma conhecimento pessoal em conhecimento organizacional. Para um gestor de projetos, esse aspecto é particularmente relevante porque continuidade não pode depender exclusivamente da permanência de determinados profissionais.
Outro ponto importante é compreender que arquitetura não deve significar burocracia excessiva. O objetivo não é produzir centenas de documentos antes de iniciar o desenvolvimento, tampouco desenhar estruturas tão sofisticadas que o próprio projeto se torne inviável. O nível de formalização precisa ser proporcional ao contexto, ao risco e à complexidade da solução. Entretanto, mesmo projetos pequenos se beneficiam quando responsabilidades são claramente compreendidas. O que precisa ser evitado é a ausência completa de planejamento técnico. Organizar antes de construir não significa interromper a velocidade de entrega; significa evitar que a velocidade inicial seja conquistada ao custo de uma lentidão crescente durante todo o restante da vida útil do sistema.
No exercício apresentado no material, existe um momento particularmente significativo em que, antes mesmo da implementação efetiva das regras de negócio, a estrutura da aplicação já estava organizada em componentes como Config, Controller, DTO, Exception, Model, Repository e Service. O próprio conteúdo utiliza uma analogia bastante pertinente ao afirmar que a casa foi organizada antes da colocação dos móveis, justamente porque um software organizado tende a ser mais fácil de manter, evoluir e desenvolver em equipe. Essa imagem resume de maneira muito clara aquilo que considero uma prática fundamental em qualquer projeto de tecnologia: estabelecer primeiro uma estrutura coerente para depois começar a preencher essa estrutura com implementação.
Por essa razão, quando participo da concepção ou avaliação de uma solução tecnológica, procuro evitar que a primeira discussão seja simplesmente sobre qual linguagem, banco ou framework será escolhido. Essas decisões são importantes, mas devem surgir dentro de um contexto arquitetural já compreendido. Primeiro é necessário entender o negócio. Depois identificar o domínio e suas entidades. Em seguida analisar fluxos, responsabilidades, integrações, dependências, persistência, segurança, disponibilidade e necessidades de crescimento. Somente então a escolha tecnológica passa a ser realmente estratégica. Quando fazemos o caminho inverso, existe o risco de tentar adaptar todo o problema às limitações ou características da ferramenta escolhida antecipadamente.
Ao longo dos anos, trabalhando diretamente com bancos de dados, sistemas corporativos, infraestrutura e projetos de transformação tecnológica, ficou cada vez mais evidente para mim que software não deve ser pensado apenas para funcionar hoje. Ele precisa ser projetado para continuar funcionando amanhã, quando a base de dados aumentar, quando novas integrações forem necessárias, quando outros profissionais assumirem sua manutenção e quando regras que hoje parecem permanentes forem modificadas pelo negócio. Essa visão muda completamente a maneira de avaliar arquitetura. Ela deixa de ser uma discussão restrita ao código e passa a fazer parte de uma estratégia mais ampla de governança, continuidade, desempenho, segurança e sustentabilidade da solução.
É possível resumir toda essa reflexão dizendo que desenvolver software e construir software sustentável são atividades relacionadas, mas não necessariamente equivalentes. Fazer uma funcionalidade operar é apenas uma etapa. Engenharia de software exige compreender por que ela funciona, onde cada responsabilidade está localizada, quais componentes serão afetados por uma alteração e como essa solução continuará sendo administrável à medida que crescer. Para mim, como DBA e gestor de projetos, essa é uma das maiores responsabilidades de quem participa de projetos tecnológicos: não olhar apenas para a próxima entrega, mas também para aquilo que acontecerá depois dela.
Projetos não fracassam somente quando um sistema para de funcionar. Muitos começam a fracassar silenciosamente quando continuam funcionando, mas se tornam tão complexos, acoplados e caros de modificar que qualquer nova necessidade passa a representar uma operação de alto risco. É nesse momento que percebemos que arquitetura nunca foi apenas uma questão de organização do código. Ela sempre esteve relacionada à capacidade de evolução, à previsibilidade da manutenção, ao controle dos riscos e à própria longevidade da solução. Escolher boas tecnologias é importante, mas organizá-las dentro de uma arquitetura coerente é o que realmente permite transformar tecnologia em uma plataforma sustentável para o negócio.
É por isso que considero que uma das perguntas mais importantes antes de iniciar qualquer projeto não deve ser simplesmente “qual tecnologia vamos utilizar?”, mas sim “como vamos organizar esta solução para que ela continue compreensível, segura, sustentável e preparada para evoluir?”. Quando essa pergunta é respondida de forma responsável, a linguagem, o framework e o banco de dados deixam de ser decisões isoladas e passam a fazer parte de uma estratégia tecnológica maior. E é exatamente nesse ponto que arquitetura, engenharia de software, administração de banco de dados e gestão de projetos deixam de atuar como disciplinas independentes e passam a trabalhar juntas para aquilo que realmente importa: construir soluções que entreguem valor hoje sem comprometer a capacidade de entregar valor amanhã.
