Aikido

Was wir von Strapis Codebase gelernt haben: 20 Code-Review-Regeln für skalierbare Entwicklung

Einführung

Strapi ist eine der beliebtesten Open-Source-Plattformen für Headless CMS, aber es ist auch eine riesige Codebasis mit Hunderten von Mitwirkenden und Tausenden von Pull-Requests. Es ist nicht einfach, die Qualität eines so großen Projekts hoch zu halten. Es bedarf klarer und konsistenter Code-Review-Regeln, um sicherzustellen, dass jeder Beitrag zuverlässig, lesbar und sicher bleibt.

In diesem Artikel haben wir eine Reihe von Code-Review-Regeln zusammengestellt, die auf dem öffentlichen Repository von Strapi basieren. Diese Regeln stammen aus der realen Arbeit: tatsächliche Probleme, Diskussionen und Pull-Requests, die dazu beigetragen haben, dass das Projekt wächst und die Codebasis stabil bleibt.

Warum die Aufrechterhaltung der Codequalität in einem großen Open-Source-Projekt schwierig ist

Die Aufrechterhaltung der Qualität in einem großen Open-Source-Projekt ist aufgrund des schieren Umfangs und der Vielfalt der Beiträge eine Herausforderung. Hunderte oder sogar Tausende von Entwicklern, von Freiwilligen bis hin zu erfahrenen Ingenieuren, reichen Pull-Requests ein, von denen jeder neue Funktionen, Bugfixes oder Refactors einbringt. Ohne klare Regeln kann die Codebasis schnell inkonsistent, brüchig oder schwierig zu navigieren werden.

Einige der wichtigsten Herausforderungen sind:

  • Vielfältige Mitwirkende mit unterschiedlichen Erfahrungswerten.
  • Inkonsistente Kodierungsmuster zwischen den Modulen.
  • Versteckte Bugs und doppelte Logik schleichen sich ein.
  • Sicherheitsrisiken, wenn Prozesse nicht durchgesetzt werden.
  • Zeitintensive Überprüfungen für Freiwillige, die nicht mit der gesamten Codebasis vertraut sind.

Um diese Herausforderungen zu meistern, setzen erfolgreiche Projekte auf strukturierte Prozesse: gemeinsame Standards, automatisierte Werkzeuge und klare Richtlinien. Diese Praktiken sorgen für Wartbarkeit, Lesbarkeit und Sicherheit, auch wenn das Projekt wächst und mehr Mitwirkende anzieht.

Wie die Einhaltung dieser Regeln die Wartbarkeit, die Sicherheit und das Onboarding verbessert

Die Einhaltung klarer Regeln für die Codeüberprüfung wirkt sich unmittelbar auf den Erfolg Ihres Projekts aus:

  • Wartungsfreundlichkeit: Konsistente Ordnerstrukturen, Benennungskonventionen und Codierungsmuster erleichtern das Lesen, Navigieren und Erweitern der Codebasis.
  • Sicherheit: Eingabevalidierung, Bereinigung, Berechtigungsprüfungen und kontrollierter Datenbankzugriff verringern Schwachstellen und verhindern versehentliche Datenlecks.
  • Schnelleres Onboarding: Gemeinsame Standards, dokumentierte Dienstprogramme und klare Beispiele helfen neuen Mitarbeitern, das Projekt schnell zu verstehen und selbstbewusst mitzuarbeiten.

Durch die Anwendung dieser Regeln können Teams sicherstellen, dass die Codebasis skalierbar, zuverlässig und sicher bleibt, auch wenn die Zahl der Mitwirkenden wächst.

Verknüpfung von Kontext und Regeln

Bevor wir uns die Regeln ansehen, ist es wichtig zu verstehen, dass es bei einem Projekt wie Strapi nicht nur darum geht, allgemeine Best Practices zu befolgen, um die Codequalität hoch zu halten. Es geht darum, klare Muster und Standards zu haben, die Hunderten von Mitwirkenden helfen, an einem Strang zu ziehen. Jede der folgenden 20 Regeln konzentriert sich auf echte Herausforderungen, die in der Codebasis von Strapi auftreten.

Die für jede Vorschrift angeführten Beispiele veranschaulichen sowohl nicht konforme als auch konforme Ansätze und vermitteln ein klares Bild davon, wie diese Grundsätze in der Praxis anzuwenden sind.

Lassen Sie uns nun die Regeln erkunden, die Strapis Codebasis skalierbar, konsistent und qualitativ hochwertig machen, angefangen bei der Projektstruktur und den Konfigurationsstandards.

Regeln: Projektstruktur und Konsistenz

1. Befolgen Sie die von Strapi festgelegten Ordnerkonventionen

Vermeiden Sie es, Dateien zu verstreuen oder neue Strukturen zu erfinden. Halten Sie sich an das bewährte Projektlayout von Strapi, um die Navigation vorhersehbar zu halten.

Nicht konformes Beispiel

1src/
2├──controllers/
3│└── userController.js
4├──services/
5│└── userLogic.js
6├──Routen/
7│└── userRoutes.js
8└──utils/
9 └── helper.js

Konformes Beispiel

1src/
2└──api/
3 └── user/
4 ├── Kontrolleure/
5 │ └── user.js
6 ├── services/
7 │ └── user.js
8 ├── routes/
9 │ └── user.js
10 └─── content-types/
11 └─── user/schema.json

2. Konfigurationsdateien konsistent halten

Verwenden Sie in allen Konfigurationsdateien dieselbe Struktur sowie dieselben Benennungs- und Formatierungskonventionen, um Konsistenz zu gewährleisten und Fehler zu vermeiden.

Nicht konformes Beispiel

1// config/server.js
2module.exports = {
3    PORT: 1337,
4    host: '0.0.0.0',
5    APP_NAME: 'my-app'
6}
7
8// config/database.js
9export default {
10  connection: {
11    client: 'sqlite',
12    connection: { filename: '.tmp/data.db' }
13  }
14}
15
16// config/plugins.js
17module.exports = ({ env }) => ({
18   upload: { provider: "local" },
19   email: { provider: 'sendgrid' }
20});

Konformes Beispiel

1// config/server.js
2module.exports = ({ env }) => ({
3  host: env('HOST', '0.0.0.0'),
4  port: env.int('PORT', 1337),
5  app: { keys: env.array('APP_KEYS') },
6});
7
8// config/database.js
9module.exports = ({ env }) => ({
10  connection: {
11    client: 'sqlite',
12    connection: { filename: env('DATABASE_FILENAME', '.tmp/data.db') },
13    useNullAsDefault: true,
14  },
15});
16
17// config/plugins.js
18module.exports = ({ env }) => ({
19  upload: { provider: 'local' },
20  email: { provider: 'sendgrid' },
21});

3. Aufrechterhaltung einer strengen Typensicherheit

Jeder neue oder aktualisierte Code muss genaue TypeScript-Typen oder JSDoc-Definitionen enthalten. Vermeiden Sie die Verwendung beliebiger, fehlender Rückgabetypen oder impliziter Typinferenz in gemeinsam genutzten Modulen.

Nicht konformes Beispiel

1// src/api/user/services/user.ts
2export const createUser = (data) => {
3  return strapi.db.query('api::user.user').create({ data });
4};

Konformes Beispiel

1// src/api/user/services/user.ts
2import { User } from './types';
3
4export const createUser = async (data: User): Promise<User> => {
5  return await strapi.db.query('api::user.user').create({ data });
6};

4. Konsistente Benennung von Diensten und Controllern

Die Namen von Controllern und Diensten müssen eindeutig ihrer Domäne entsprechen (z. B. user.controller.js mit user.service.js).

Nicht konformes Beispiel

1src/
2└── api/
3    └── Benutzer/
4        ├── Kontrolleure/
5        │ └── mainController.js
6        ├── Dienste/
7        │ └── accountService.js
8        ├── Routen/
9        │ └── Benutzer.js

Konformes Beispiel

1src/
2└── api/
3    └── Benutzer/
4        ├── Kontrolleure/
5        │ └── Benutzer.js
6        ├── Dienste/
7        │ └── Benutzer.js
8        ├── Routen/
9        │ └── Benutzer.js
10        └── Inhalt-Typen/
11            └── Benutzer/schema.json

Regeln: Codequalität und Wartbarkeit

5. Vereinfachung des Kontrollflusses mit frühen Rückgaben

Statt tiefer if/else-Schachtelungen sollten Sie bei fehlgeschlagenen Bedingungen frühzeitig zurückkehren.

Nicht konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, author } = ctx.request.body;
5
6    if (title) {
7      if (content) {
8        if (author) {
9          const article = await strapi.db.query('api::article.article').create({
10            data: { title, content, author },
11          });
12          ctx.body = article;
13        } else {
14          ctx.throw(400, 'Missing author');
15        }
16      } else {
17        ctx.throw(400, 'Missing content');
18      }
19    } else {
20      ctx.throw(400, 'Missing title');
21    }
22  },
23};

Konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, author } = ctx.request.body;
5
6    if (!title) ctx.throw(400, 'Missing title');
7    if (!content) ctx.throw(400, 'Missing content');
8    if (!author) ctx.throw(400, 'Missing author');
9
10    const article = await strapi.db.query('api::article.article').create({
11      data: { title, content, author },
12    });
13
14    ctx.body = article;
15  },
16};

6. Vermeiden Sie übermäßige Verschachtelungen in Controllern

Vermeiden Sie große Blöcke mit verschachtelter Logik innerhalb von Controllern oder Diensten. Extrahieren Sie wiederholte oder komplexe Bedingungen in gut benannte Hilfsfunktionen oder Dienstprogramme.

Nicht konformes Beispiel

1// src/api/order/controllers/order.js
2module.exports = {
3  async create(ctx) {
4    const { items, user } = ctx.request.body;
5
6    if (user && user.role === 'customer') {
7      if (items && items.length > 0) {
8        const stock = await strapi.service('api::inventory.inventory').checkStock(items);
9        if (stock.every((i) => i.available)) {
10          const order = await strapi.db.query('api::order.order').create({ data: { items, user } });
11          ctx.body = order;
12        } else {
13          ctx.throw(400, 'Some items are out of stock');
14        }
15      } else {
16        ctx.throw(400, 'No items in order');
17      }
18    } else {
19      ctx.throw(403, 'Unauthorized user');
20    }
21  },
22};

Konformes Beispiel

1// src/api/order/utils/validation.js
2const isCustomer = (user) => user?.role === 'customer';
3const hasItems = (items) => Array.isArray(items) && items.length > 0;
4
5// src/api/order/controllers/order.js
6module.exports = {
7  async create(ctx) {
8    const { items, user } = ctx.request.body;
9
10    if (!isCustomer(user)) ctx.throw(403, 'Unauthorized user');
11    if (!hasItems(items)) ctx.throw(400, 'No items in order');
12
13    const stock = await strapi.service('api::inventory.inventory').checkStock(items);
14    const allAvailable = stock.every((i) => i.available);
15    if (!allAvailable) ctx.throw(400, 'Some items are out of stock');
16
17    const order = await strapi.db.query('api::order.order').create({ data: { items, user } });
18    ctx.body = order;
19  },
20};

7. Geschäftslogik aus den Controllern heraushalten

Controller sollten schlank bleiben und nur Anfragen orchestrieren. Verschieben Sie die Geschäftslogik in Dienste.

Nicht konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const { title, content, authorId } = ctx.request.body;
5
6    const author = await strapi.db.query('api::author.author').findOne({ where: { id: authorId } });
7    if (!author) ctx.throw(400, 'Author not found');
8
9    const timestamp = new Date().toISOString();
10    const slug = title.toLowerCase().replace(/\s+/g, '-');
11
12    const article = await strapi.db.query('api::article.article').create({
13      data: { title, content, slug, publishedAt: timestamp, author },
14    });
15
16    await strapi.plugins['email'].services.email.send({
17      to: author.email,
18      subject: `New article: ${title}`,
19      html: `<p>${content}</p>`,
20    });
21
22    ctx.body = article;
23  },
24};

Konformes Beispiel

1// src/api/article/controllers/article.js
2module.exports = {
3  async create(ctx) {
4    const article = await strapi.service('api::article.article').createArticle(ctx.request.body);
5    ctx.body = article;
6  },
7};
// src/api/article/services/article.js
module.exports = ({ strapi }) => ({
  async createArticle(data) {
    const { title, content, authorId } = data;

    const author = await strapi.db.query('api::author.author').findOne({ where: { id: authorId } });
    if (!author) throw new Error('Author not found');

    const slug = title.toLowerCase().replace(/\s+/g, '-');
    const article = await strapi.db.query('api::article.article').create({
      data: { title, content, slug, author },
    });

    await strapi.plugins['email'].services.email.send({
      to: author.email,
      subject: `New article: ${title}`,
      html: `<p>${content}</p>`,
    });

    return article;
  },
});

8. Nutzenfunktionen für wiederkehrende Muster verwenden

Doppelte Muster (z.B. Validierung, Formatierung) sollten in gemeinsamen Dienstprogrammen untergebracht werden.

Nicht konformes Beispiel

// src/api/article/controllers/article.js
module.exports = {
  async create(ctx) {
    const { title } = ctx.request.body;
    const slug = title.toLowerCase().replace(/\s+/g, '-');
    ctx.body = await strapi.db.query('api::article.article').create({ data: { ...ctx.request.body, slug } });
  },
};

// src/api/event/controllers/event.js
module.exports = {
  async create(ctx) {
    const { name } = ctx.request.body;
    const slug = name.toLowerCase().replace(/\s+/g, '-');
    ctx.body = await strapi.db.query('api::event.event').create({ data: { ...ctx.request.body, slug } });
  },
};

Konformes Beispiel

// src/utils/slugify.js
modul.exports = (text) => text.toLowerCase().trim().replace(/\s+/g, '-');
// src/api/article/controllers/article.js
const slugify = require('../../../utils/slugify');

module.exports = {
  async create(ctx) {
    const { title } = ctx.request.body;
    const slug = slugify(title);
    ctx.body = await strapi.db.query('api::article.article').create({ data: { ...ctx.request.body, slug } });
  },
};

9. Debugging-Protokolle vor der Produktion entfernen

Verwenden Sie console.log, console.warn oder console.error nicht im Produktionscode. Verwenden Sie immer strapi.log oder einen konfigurierten Logger, um sicherzustellen, dass die Protokolle die Umgebungseinstellungen respektieren und keine sensiblen Informationen preisgeben.

Nicht konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async find(ctx) {
    console.log('Request received:', ctx.request.body); // Unsafe in production
    const users = await strapi.db.query('api::user.user').findMany();
    console.log('Users fetched:', users.length);
    ctx.body = users;
  },
};

Konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async find(ctx) {
    strapi.log.info(`Fetching users for request from ${ctx.state.user?.email || 'anonymous'}`);
    const users = await strapi.db.query('api::user.user').findMany();
    strapi.log.debug(`Number of users fetched: ${users.length}`);
    ctx.body = users;
  },
};
if (process.env.NODE_ENV === 'development') {
  strapi.log.debug('Request body:', ctx.request.body);
}

Regeln: Datenbank- und Abfragepraktiken

10. Vermeiden Sie rohe SQL-Abfragen

Verwenden Sie immer eine konsistente Abfragemethode auf hoher Ebene (z. B. ein ORM oder einen Query Builder), um die Wartbarkeit zu gewährleisten, Regeln/Hooks durchzusetzen und Sicherheitsrisiken zu verringern.

Nicht konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async findActiveUsers() {
    const knex = strapi.db.connection; 
    const result = await knex.raw('SELECT * FROM users WHERE active = true'); // Raw SQL
    return result.rows;
  },
};

Konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async findActiveUsers() {
    return await strapi.db.query('api::user.user').findMany({
      where: { active: true },
    });
  },
};

11. Strapis Abfragemaschine konsequent nutzen

Mischen Sie nicht verschiedene Datenbankzugriffsmethoden (z.B. ORM-Aufrufe vs. Rohabfragen) innerhalb desselben Features. Verwenden Sie einen einzigen, konsistenten Abfrageansatz, um Wartbarkeit, Lesbarkeit und vorhersehbares Verhalten zu gewährleisten.

Nicht konformes Beispiel

// src/api/order/services/order.js
module.exports = {
  async getPendingOrders() {
    // Using entityService
    const orders = await strapi.entityService.findMany('api::order.order', {
      filters: { status: 'pending' },
    });

    // Mixing with raw db query
    const rawOrders = await strapi.db.connection.raw('SELECT * FROM orders WHERE status = "pending"');

    return { orders, rawOrders };
  },
};

Konformes Beispiel

// src/api/order/services/order.js
module.exports = {
  async getPendingOrders() {
    return await strapi.db.query('api::order.order').findMany({
      where: { status: 'pending' },
    });
  },
};

12. Optimieren der Datenbankaufrufe

Stapeln Sie zusammenhängende Datenbankabfragen oder kombinieren Sie sie zu einem einzigen Vorgang, um Leistungsengpässe zu vermeiden und unnötige sequenzielle Aufrufe zu reduzieren.

Nicht konformes Beispiel

async function getArticlesWithAuthors() {
  const articles = await db.query('articles').findMany();

  // Fetch author for each article sequentially
  for (const article of articles) {
    article.author = await db.query('authors').findOne({ id: article.authorId });
  }

  return articles;
}

Konformes Beispiel

async function getArticlesWithAuthors() {
  return await db.query('articles').findMany({ populate: ['author'] });
}

Regeln: API und Sicherheit

13. Validierung von Eingaben mit Strapi-Validatoren

Validieren Sie alle eingehenden Daten mit einem konsistenten Validierungsmechanismus, bevor Sie sie in Controllern, Diensten oder Datenbankoperationen verwenden.

Nicht konformes Beispiel

async function createUser(req, res) {
  const { username, email } = req.body;

  // Directly inserting into database without validation
  const user = await db.query('users').create({ username, email });
  res.send(user);
}

Konformes Beispiel

const Joi = require('joi');

async function createUser(req, res) {
  const schema = Joi.object({
    username: Joi.string().min(3).required(),
    email: Joi.string().email().required(),
  });

  const { error, value } = schema.validate(req.body);
  if (error) return res.status(400).send(error.details);

  const user = await db.query('users').create(value);
  res.send(user);
}

14. Benutzereingaben vor dem Speichern bereinigen

Bereinigen Sie alle Eingaben, bevor Sie sie in der Datenbank speichern oder an andere Systeme weitergeben.

Nicht konformes Beispiel

async function createComment(req, res) {
  const { text, postId } = req.body;

  // Directly saving data
  const comment = await db.query('comments').create({ text, postId });
  res.send(comment);
}

Konformes Beispiel

const sanitizeHtml = require('sanitize-html');

async function createComment(req, res) {
  const { text, postId } = req.body;

  const sanitizedText = sanitizeHtml(text, { allowedTags: [], allowedAttributes: {} });

  const comment = await db.query('comments').create({ text: sanitizedText, postId });
  res.send(comment);
}

15. Erlaubnisprüfungen durchsetzen

Wenden Sie Berechtigungsprüfungen auf jede geschützte Route an, um sicherzustellen, dass nur autorisierte Benutzer darauf zugreifen können.

Nicht konformes Beispiel

async function deleteUser(req, res) {
  const { userId } = req.params;

  // No check for admin or owner
  await db.query('users').delete({ id: userId });
  res.send({ success: true });
}

Konformes Beispiel

async function deleteUser(req, res) {
  const { userId } = req.params;
  const requestingUser = req.user;

  // Allow only admins or the owner
  if (!requestingUser.isAdmin && requestingUser.id !== userId) {
    return res.status(403).send({ error: 'Forbidden' });
  }

  await db.query('users').delete({ id: userId });
  res.send({ success: true });
}

16. Konsistente Fehlerbehandlung mit Boom

Konsistente Behandlung von Fehlern über alle API-Routen hinweg unter Verwendung eines zentralen oder einheitlichen Fehlerbehandlungsmechanismus.

Nicht konformes Beispiel

async function getUser(req, res) {
  const { id } = req.params;

  try {
    const user = await db.query('users').findOne({ id });
    if (!user) res.status(404).send('User not found'); // raw string error
    else res.send(user);
  } catch (err) {
    res.status(500).send(err.message); // different error format
  }
}

Konformes Beispiel

const { createError } = require('../utils/errors');

async function getUser(req, res, next) {
  try {
    const { id } = req.params;
    const user = await db.query('users').findOne({ id });

    if (!user) throw createError(404, 'User not found');

    res.send(user);
  } catch (err) {
    next(err); // passes error to centralized error handler
  }
}
// src/utils/errors.js
function createError(status, message) {
  return { status, message };
}

function errorHandler(err, req, res, next) {
  res.status(err.status || 500).json({ error: err.message });
}

module.exports = { createError, errorHandler };

Regeln: Prüfung und Dokumentation

17. Hinzufügen oder Aktualisieren von Tests für jede Funktion

Neuer Code ohne Tests wird nicht zusammengeführt, Tests sind Teil der Definition von "done".

Nicht konformes Beispiel

// src/api/user/services/user.js
module.exports = {
  async createUser(data) {
    const user = await db.query('users').create(data);
    return user;
  },
};

// No test file exists for this service

Konformes Beispiel

// tests/user.service.test.js
const { createUser } = require('../../src/api/user/services/user');

describe('User Service', () => {
  it('should create a new user', async () => {
    const mockData = { username: 'testuser', email: 'test@example.com' };
    const result = await createUser(mockData);

    expect(result).toHaveProperty('id');
    expect(result.username).toBe('testuser');
    expect(result.email).toBe('test@example.com');
  });
});

18. Neue Endpunkte dokumentieren

Jede API-Ergänzung muss vor dem Merge in den Referenzdokumenten dokumentiert werden.

Nicht konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  async deactivate(ctx) {
    const { userId } = ctx.request.body;
    await db.query('users').update({ id: userId, active: false });
    ctx.body = { success: true };
  },
};

// No update in API reference or docs

Konformes Beispiel

// src/api/user/controllers/user.js
module.exports = {
  /**
   * Deactivate a user account.
   * POST /users/deactivate
   * Body: { userId: string }
   * Response: { success: boolean }
   * Errors: 400 if userId missing, 404 if user not found
   */
  async deactivate(ctx) {
    const { userId } = ctx.request.body;
    if (!userId) ctx.throw(400, 'userId is required');

    const user = await db.query('users').findOne({ id: userId });
    if (!user) ctx.throw(404, 'User not found');

    await db.query('users').update({ id: userId, active: false });
    ctx.body = { success: true };
  },
};

Referenzdokumente aktualisieren Beispiel:

### POST /users/deactivate

**Request Body:**
```json
{
  "userId": "string"
}

Antwort:

{
  "success": true
}

Irrtümer:

  • 400: userId ist erforderlich
  • 404: Benutzer nicht gefunden
Warum das funktioniert:  
- Entwickler und API-Nutzer können Endpunkte zuverlässig erkennen und nutzen  
- Sicherstellung der Konsistenz zwischen Implementierung und Dokumentation  
- Erleichtert Wartung und Einarbeitung  

---

Soll ich als Nächstesmit **Regel Nr.19 ("JSDoc für gemeinsam genutzte Dienstprogramme verwenden")** im gleichen Formatfortfahren?

19. JSDoc für gemeinsame Dienstprogramme verwenden

Gemeinsame Funktionen sollten mit JSDoc erklärt werden, um das Onboarding und die Zusammenarbeit zu erleichtern.

Nicht konformes Beispiel

// src/utils/slugify.js
function slugify(text) {
  return text.toLowerCase().trim().replace(/\s+/g, '-');
}

module.exports = slugify;

Konformes Beispiel

// src/utils/slugify.js

/**
 * Converts a string into a URL-friendly slug.
 *
 * @param {string} text - The input string to convert.
 * @returns {string} A lowercased, trimmed, dash-separated slug.
 */
function slugify(text) {
  return text.toLowerCase().trim().replace(/\s+/g, '-');
}

module.exports = slugify;

20. Aktualisieren Sie das Änderungsprotokoll mit jedem wichtigen PR

Aktualisieren Sie das Änderungsprotokoll des Projekts mit jeder wichtigen Funktion, Fehlerbehebung oder API-Änderung, bevor Sie einen PR zusammenführen.

Nicht konformes Beispiel

# CHANGELOG.md

## [1.0.0] -  2025-09-01
- Erste Veröffentlichung

Konformes Beispiel

# CHANGELOG.md

## [1.1.0] -  2025-10-06
- Endpunkt zur Benutzerdeaktivierung hinzugefügt (`POST /users/deactivate`)
- Fehler in der Slug-Generierung für Artikeltitel behoben
- E-Mail-Benachrichtigungsdienst aktualisiert, um Batch-Versand zu ermöglichen

Schlussfolgerung

Wir haben das öffentliche Repository von Strapi untersucht, um zu verstehen, wie konsistente Codemuster großen Open-Source-Projekten helfen, ohne Qualitätsverlust zu wachsen. Diese 20 Regeln sind keine Theorie. Es sind praktische Lektionen, die direkt aus der Codebasis von Strapi entnommen wurden und das Projekt einfacher zu pflegen, sicherer und lesbarer machen.

Wenn Ihr Projekt wächst, sollten Sie diese Lektionen bei Ihren Code-Reviews anwenden. Sie werden Ihnen helfen, weniger Zeit mit dem Bereinigen von unordentlichem Code zu verbringen und mehr Zeit mit der Entwicklung von Funktionen, die wirklich wichtig sind.

FAQs

Haben Sie Fragen?

Warum sind Code-Review-Regeln in Open-Source-Projekten wie Strapi wichtig?

Da Hunderte von Entwicklern mitwirken, verhindern einheitliche Überprüfungsregeln ein Chaos. Sie stellen sicher, dass jede Pull-Anfrage der gleichen Struktur, Benennung und den gleichen Sicherheitsmustern folgt, wodurch das Projekt im Laufe der Zeit stabil und wartbar bleibt.

Wie erhält Strapi die Codequalität in großem Umfang aufrecht?

Strapi verwendet strenge Ordnerkonventionen, TypeScript-Übernahme, automatisierte Tests und standardisierte Validierung. Jede Änderung wird vor dem Zusammenführen auf Klarheit, Leistung und Sicherheit geprüft.

Was ist der Unterschied zwischen Linting und Code-Review-Regeln?

Linting fängt Syntax- und Formatierungsprobleme automatisch auf. Die Regeln für die Codeüberprüfung gehen tiefer: Sie befassen sich mit der Architektur, der Lesbarkeit, der Klarheit der Namensgebung, der Wartbarkeit und der Sicherheit, die Tools ohne menschlichen oder künstlichen Kontext nicht erkennen können.

Wie können Teams diese Regeln auf ihre eigenen Projekte anwenden?

- Dokumentieren Sie Ihre Überprüfungsstandards.
- Fügen Sie automatisierte Überprüfungen und PR-Vorlagen hinzu.
- Verwenden Sie konsistente Benennungen und Ordnerstrukturen.
- Erzwingen Sie Tests und Dokumentationsaktualisierungen bei jeder Zusammenführung.
- Führen Sie KI-basierte Codeüberprüfungswerkzeuge wie Aikido Code Quality aus, um Designprobleme auf höchster Ebene zu erkennen.

Welche Tools können helfen, die Regeln für die Codeüberprüfung automatisch durchzusetzen?

Tools wie Aikido Security Code Quality helfen bei der Erkennung von Architektur-, Wartbarkeits- und Sicherheitsproblemen während der Codeüberprüfung und gehen damit weit über das traditionelle Linting hinaus.

Was ist die größte Herausforderung bei der Pflege der Codebasis von Strapi?

Gleichgewicht zwischen Innovation und Konsistenz - neue Mitarbeiter bringen frische Ideen ein, aber ohne klare Regeln läuft das Projekt Gefahr, in inkonsistente Muster und schwer zu wartenden Code abzugleiten.

Wie verbessern diese Regeln das Onboarding für neue Mitarbeiter?

Sie bieten einen klaren Fahrplan der Erwartungen. Wenn die Ordnerstruktur, die Benennung und die Dokumentation vorhersehbar sind, können neue Entwickler schnell verstehen, wie sie einen Beitrag leisten können, ohne bestehende Muster zu durchbrechen.

Starten Sie kostenlos

Sichern Sie Ihren Code, Cloud und die Laufzeit in einem zentralen System.
Finden und beheben Sie Schwachstellen schnell  automatisch.

Keine Kreditkarte erforderlich | Scanergebnisse in 32 Sekunden.