Skip to content

Estrutura e Organização de Código

Para abordar a estrutura e organização do código, especialmente quando falamos de melhorar a manutenção e organização em um contexto de um projeto Mirage JS, é crucial entender como uma boa estrutura de diretórios e práticas de codificação podem influenciar diretamente na escalabilidade e manutenibilidade do seu projeto. Vamos desmembrar isso em partes:

1. Melhorando a Manutenção do Código

Manter um código limpo e bem organizado é essencial para que ele seja fácil de entender, modificar e testar. Aqui estão algumas práticas recomendadas:

  • Modularidade: Divida o código em módulos ou componentes com responsabilidades claramente definidas. Isso não apenas facilita o entendimento do código, mas também permite reusá-lo.
  • Princípio de Responsabilidade Única: Cada módulo ou função deve ter um e único motivo para mudar. Isso ajuda a evitar o acoplamento e facilita os testes.
  • Convenções de Codificação: Mantenha um padrão de nomenclatura e estilização. Isso ajuda novos desenvolvedores a se familiarizarem com o código mais rapidamente.
  • Documentação: Comente o código quando necessário e mantenha uma documentação atualizada, o que é vital para projetos em equipe.

2. Organizando Arquivos e Pastas no Mirage JS

Mirage JS é uma biblioteca de simulação de API que permite que front-end developers construam, testem e compartilhem uma aplicação completa antes mesmo do back-end estar pronto. A organização de arquivos em um projeto Mirage JS pode seguir a seguinte estrutura, assumindo que você está:

plaintext
/src
  /mirage
    - @types           # Tipos personalizados para Mirage
      - index.d.ts
    /factories         # Fábricas para gerar dados de teste
      - index.ts
      - utils.ts
      - userFactory.ts
      - postFactory.ts
    /fixtures          # Dados fixos iniciais para o desenvolvimento
      - index.ts
      - users.json
    /models            # Modelos Mirage representando dados
      - index.ts
    /routes            # Definição de rotas Mirage
      - index.ts
    /seeds             # Dados iniciais para carregar no servidor Mirage
      - index.ts
    - server.ts        # Configuração do servidor Mirage
  • @types: Pasta opcional para definir tipos personalizados para Mirage JS.
  • factories: Permite a criação de dados de maneira programática para testes e desenvolvimento.
  • fixtures: Dados estáticos que podem ser usados para carregar estados iniciais.
  • models: Define os modelos de dados que imitam sua API backend.
  • routes: Define as rotas Mirage que correspondem às rotas da sua API backend.
  • seeds: Dados iniciais que podem ser carregados no servidor Mirage para simular um estado inicial.
  • server.ts: Arquivo onde o servidor Mirage é configurado e inicializado.

3. Exemplo Prático: Criacão dos arquivos

Vamos criar um exemplo prático para ilustrar a organização de arquivos e pastas em um projeto Mirage JS. Suponha que você tenha um aplicativo de gerenciamento de usuários e deseja simular uma API backend usando Mirage JS. Aqui está como você pode organizar seus arquivos:

@types/index.d.ts

typescript
// src/mirage/@types/index.d.ts
export type Post = {
  id: number;
  title: string;
  content: string;
  userId: number;
};

export type User = {
  id: number;
  name: string;
  email: string;
  role: "admin" | "user";
  posts: Post[];
};

factories/index.ts

typescript
// src/mirage/factories/index.ts
import userFactory from "./userFactory";
import postFactory from "./postFactory";

/*
 * factories are contained in a single object, that's why we
 * destructure what's coming from users and the same should
 * be done for all future factories
 */
export default {
  ...userFactory,
  ...postFactory,
};

factories/utils.ts

typescript
// src/mirage/factories/utils.ts
import { v4 as uuid } from "uuid";
import { faker } from "@faker-js/faker";

export const randomNumber = (quantity: number) =>
  Math.floor(Math.random() * quantity) + 1;

export const randomUUID = () => {
  return uuid();
};

factories/userFactory.ts

typescript
// src/mirage/factories/userFactory.ts
import type { Server, ModelInstance } from "miragejs";
import type { User } from "../@types";
/*
 * Mirage JS guide on Factories: https://miragejs.com/docs/data-layer/factories
 */
import { Factory } from "miragejs";
import { randomNumber } from "./utils";

/*
 * Faker Github repository: https://github.com/Marak/Faker.js#readme
 */
import { faker } from "@faker-js/faker";

export default {
  user: Factory.extend<
    Partial<
      User & {
        posts: ModelInstance[];
        afterCreate: (user: ModelInstance, server: Server) => void;
      }
    >
  >({
    name() {
      return faker.person.fullName();
    },
    email() {
      return faker.internet.email();
    },
    role() {
      return faker.helpers.arrayElements(["admin", "user"], 1)[0];
    },
    afterCreate(user: ModelInstance, server: Server) {
      const posts = server.createList("post", randomNumber(5));
      user.update({ posts });
    },
  }),
};

factories/postFactory.ts

typescript
// src/mirage/factories/postFactory.ts
/*
 * Mirage JS guide on Factories: https://miragejs.com/docs/data-layer/factories
 */
import { Factory } from "miragejs";

/*
 * Faker Github repository: https://github.com/Marak/Faker.js#readme
 */
import { faker } from "@faker-js/faker";

export default {
  post: Factory.extend({
    title() {
      return faker.lorem.words(3);
    },
    content() {
      return faker.lorem.paragraphs(3);
    },
  }),
};

fixtures/index.ts

typescript
// src/mirage/fixtures/index.ts
/*
 * Mirage JS guide on Fixtures: https://miragejs.com/docs/data-layer/fixtures
 */

import users from "./users.json";

export default { users };

fixtures/users.json

json
// src/mirage/fixtures/users.json
[
  {
    "id": 1,
    "name": "John Doe",
    "email": "john@email.com",
    "role": "admin",
    "posts": [
      {
        "id": 1,
        "title": "Hello, World!",
        "content": "This is a test post.",
        "userId": 1
      }
    ]
  },
  {
    "id": 2,
    "name": "Jane Doe",
    "email": "jane@email.com",
    "role": "user",
    "posts": []
  }
]

models/index.ts

typescript
// src/mirage/models/index.ts
/*
 * Mirage JS guide on Models: https://miragejs.com/docs/data-layer/models
 */

import { Model, hasMany } from "miragejs";

/*
 * Everytime you create a new resource you have
 * to create a new Model and add it here. It is
 * true for Factories and for Fixtures.
 *
 * Mirage JS guide on Relationships: https://miragejs.com/docs/main-concepts/relationships/
 */
export default {
  user: Model.extend({
    posts: hasMany(),
  }),
  post: Model,
};

routes/index.ts

typescript
// src/mirage/routes/index.ts
import type { Server } from "miragejs";

import { Response } from "miragejs";

const timing = 0;
/*
 * Mirage JS guide on Routes: https://miragejs.com/docs/route-handlers/functions
 */
export default function routes(this: Server) {
  /*
   * A resource comprises all operations for a CRUD
   * operation. .get(), .post(), .put() and delete().
   * Mirage JS guide on Resource: https://miragejs.com/docs/route-handlers/shorthands#resource-helper
   */

  // CRUD operações para usuários
  this.resource("users", {
    timing,
  });
  // CRUD operações para posts
  this.resource("posts", {
    timing,
  });
}

seeds/index.ts

typescript
// src/mirage/seeds/index.ts
/*
 * Mirage JS guide on Seeds: https://miragejs.com/docs/data-layer/factories#in-development
 */
import type { Server } from "miragejs";
import { randomNumber } from "../factories/utils";

const postSeeder = (server: Server) => {
  server.createList("post", randomNumber(5));
};

export default function seeds(server: Server) {
  server.loadFixtures();
  postSeeder(server);
}

server.ts

typescript
// src/mirage/server.ts
import { Server } from "miragejs";
import factories from "./factories";
import fixtures from "./fixtures";
import routes from "./routes";
import models from "./models";
import seeds from "./seeds";
const { VITE_APP_API_URL } = import.meta.env;

const config = (environment: string) => {
  const config = {
    namespace: VITE_APP_API_URL,
    environment,
    factories,
    fixtures,
    models,
    routes,
    seeds,
  };

  return config;
};

/**
 * Cria um servidor MirageJS com base no ambiente fornecido.
 * @param {Object} options - Opções para criar o servidor.
 * @param {string} options.environment - O ambiente no qual o servidor será criado. O padrão é 'development'.
 * @returns {Server} O servidor MirageJS criado.
 */
export function criarServidor({ environment = "development" } = {}) {
  return new Server(config(environment));
}

Este processo de refatoração não apenas limpa o código e reduz a duplicidade, mas também melhora significativamente a manutenção ao centralizar a lógica de dados e usando o poder do TypeScript para segurança de tipo.