Pular para o conteúdo
SEO

Desenhando a Estrutura de um Sistema Web: Guia Visual para Iniciantes

Admin5 min de leitura
Desenhando a Estrutura de um Sistema Web: Guia Visual para Iniciantes

Desenhando a Estrutura de um Sistema Web: Guia Visual para Iniciantes

Objetivo: Este artigo mostra, de forma didática e visual, como dividir um sistema web em camadas bem definidas, escolher um padrão de projeto adequado (como MVC) e colocar tudo em prática com um exemplo completo em Node.js. Ideal para desenvolvedores que dão os primeiros passos na arquitetura de software.

Tecnologia e Inovação

📖 Introdução

Quando você cria seu primeiro aplicativo web, a tentação é colocar tudo em um único arquivo e deixar o código crescer desordenado. Essa abordagem funciona para protótipos, mas rapidamente se transforma em dor de cabeça: manutenção difícil, acoplamento excessivo e risco de bugs aumentam exponencialmente.

A arquitetura de software oferece um mapa para organizar o código em camadas com responsabilidades claras. Ao seguir um padrão como o MVC (Model‑View‑Controller), você ganha:

Separação de responsabilidades – cada parte do sistema tem um papel bem definido. Facilidade de teste e evolução – mudar a camada de dados não afeta a interface do usuário. Escalabilidade – novos recursos são adicionados sem refatorar tudo.

Neste guia, vamos:

  • Entender as camadas essenciais de uma aplicação web.
  • Conhecer os padrões de projeto mais indicados para iniciantes.
  • Montar, passo a passo, um projeto real usando Node.js, Express e SQLite.
  • Explorar extensões práticas (serviços, repositórios, validações).
  • Vamos ao desenho da arquitetura!


    1️⃣ Entendendo as Camadas de uma Aplicação Web

    Dica: Pense em uma camada como um “departamento” da sua empresa. Cada departamento tem sua própria função, mas todos colaboram para entregar o produto final.

    CamadaResponsabilidade principalTecnologias típicas (exemplo)
    ApresentaçãoInterface com o usuário (HTML, CSS, JS).EJS, Handlebars, React, Vue
    NegóciosRegras de negócio, validações, orquestração de fluxo.Serviços, Controllers
    PersistênciaAcesso a bancos de dados, leitura/escrita de registros.SQLite, PostgreSQL, ORM (Sequelize)

    1.1 Camada de Apresentação (View)

    Responsável por receber a requisição do navegador e devolver uma resposta visual. Nessa camada, evitamos lógica de negócio; usamos apenas templates que recebem dados já processados.

    1.2 Camada de Negócios (Controller / Service)

    Aqui mora a lógica de domínio: cálculos, regras de validação, fluxo de processos. Controllers recebem a requisição da camada de apresentação, chamam os serviços e retornam o resultado.

    1.3 Camada de Persistência (Model / Repository)

    Abstrai o acesso ao banco de dados. Em vez de escrever SQL espalhado pelo código, criamos repositórios que expõem métodos como findById, save, delete.

    Diagrama de Alto Nível

    Desenvolvimento e Código

    O diagrama acima ilustra a comunicação entre as três camadas, mostrando como a camada de apresentação nunca toca diretamente o banco de dados.


    2️⃣ Padrões de Projeto Mais Usados no Início

    Embora existam dezenas de padrões, alguns são especialmente úteis para quem está começando. Vamos analisar três deles e comparar suas características.

    2.1 MVC (Model‑View‑Controller)

    Model: Representa os dados e a lógica de persistência. View: Renderiza a interface. Controller: Recebe a requisição, invoca o Model e devolve a View.

    Prós: Simples, amplamente suportado por frameworks. Contras: Pode se tornar “fat controller” se a lógica não for delegada a serviços.

    2.2 MVP (Model‑View‑Presenter)

    Semelhante ao MVC, mas o Presenter contém toda a lógica de UI, mantendo a View “passiva”. É comum em aplicações desktop ou mobile, mas menos usado em web tradicional.

    2.3 Clean Architecture (versão simplificada)

    Divide o código em círculos concêntricos: Entidades, Casos de Uso, Interface de Entrada, Interface de Saída. Para iniciantes, pode ser complexo, mas vale a pena conhecer os conceitos de dependência invertida.

    Tabela Comparativa

    PadrãoCamada de UIOnde fica a lógica de negócioFacilidade de início
    MVCViewController / Service★★★★★
    MVPView (passiva)Presenter★★★★
    Clean (simpl.)ViewUse Cases / Interactors★★☆☆☆

    Recomendação: Para o primeiro projeto, MVC oferece o melhor equilíbrio entre estrutura e simplicidade.


    3️⃣ Montando um Projeto de Exemplo – Passo a Passo

    Vamos criar um pequeno sistema de gerenciamento de tarefas (To‑Do List) usando:

    Node.js (runtime) Express (framework web) EJS (template engine) SQLite (banco leve, sem necessidade de servidor)

    3.1 Preparação do Ambiente

    # Crie a pasta do projeto e entre nela
    

    mkdir todo-mvc && cd todo-mvc

    Inicialize o npm

    npm init -y

    Instale as dependências

    npm install express ejs sqlite3

    3.2 Estrutura de Pastas

    todo-mvc/
    

    ├─ src/ │ ├─ controllers/ │ │ └─ taskController.js │ ├─ models/ │ │ └─ taskModel.js │ ├─ services/ │ │ └─ taskService.js │ ├─ routes/ │ │ └─ taskRoutes.js │ ├─ views/ │ │ ├─ layout.ejs │ │ └─ tasks.ejs │ └─ app.js ├─ data/ │ └─ tasks.db # Banco SQLite (gerado em tempo de execução) └─ package.json

    Observação: A divisão acima segue o padrão MVC + Service, facilitando a manutenção.

    3.3 Código da Camada de Persistência – taskModel.js

    ``js // src/models/taskModel.js const sqlite = require('sqlite3').verbose(); const path = require('path');

    const DB_PATH = path.resolve(__dirname, '../../data/tasks.db');

    // Garante que o banco e a tabela existam const initDb = () => { const db = new sqlite.Database(DB_PATH); db.run( CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, completed INTEGER NOT NULL DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ); return db; };

    class TaskModel { constructor() { this.db = initDb(); }

    all() { return new Promise((resolve, reject) => { this.db.all('SELECT FROM tasks ORDER BY created_at DESC', (err, rows) => { if (err) return reject(err); resolve(rows); }); }); }

    find(id) { return new Promise((resolve, reject) => { this.db.get('SELECT FROM tasks WHERE id = ?', [id], (err, row) => { if (err) return reject(err); resolve(row); }); }); }

    create(title) { return new Promise((resolve, reject) => { this.db.run( 'INSERT INTO tasks (title) VALUES (?)', [title], function (err) { if (err) return reject(err); resolve({ id: this.lastID, title, completed: 0 }); } ); }); }

    update(id, fields) { const sets = Object.keys(fields) .map(k => ${k} = ?`)

    Artigos relacionados