Aikido

Ce que nous avons appris de la base de code de Strapi : 20 règles de revue de code pour un développement scalable

Introduction

Strapi est l'une des plateformes CMS headless open-source les plus populaires, mais c'est aussi une immense base de code avec des centaines de contributeurs et des milliers de pull requests. Maintenir la qualité d'un projet d'une telle envergure n'est pas facile. Cela nécessite des règles de revue de code claires et cohérentes pour garantir que chaque contribution reste fiable, lisible et sécurisée.

Dans cet article, nous avons compilé un ensemble de règles de revue de code basées sur le dépôt public de Strapi. Ces règles proviennent de travaux réels : des problèmes concrets, des discussions et des pull requests qui ont aidé le projet à se développer tout en maintenant la stabilité de la base de code.

Pourquoi il est difficile de maintenir la qualité du code dans un grand projet open source

Maintenir la qualité dans un grand projet open source est un défi en raison de l'ampleur et de la diversité des contributions. Des centaines, voire des milliers de développeurs, des bénévoles aux ingénieurs expérimentés, soumettent des pull requests, chacune introduisant de nouvelles fonctionnalités, des corrections de bugs ou des refactorisations. Sans règles claires, la base de code peut rapidement devenir incohérente, fragile ou difficile à naviguer.

Parmi les principaux défis, on trouve :

  • Contributeurs diversifiés avec des niveaux d'expérience variés.
  • Modèles de codage incohérents entre les modules.
  • Bugs cachés et logique dupliquée qui s'insinuent.
  • Risques de sécurité si les processus ne sont pas appliqués.
  • Revues chronophages pour les volontaires peu familiers avec l'ensemble du codebase.

Pour relever ces défis, les projets réussis s'appuient sur des processus structurés : des standards partagés, un outillage automatisé et des directives claires. Ces pratiques garantissent la maintenabilité, la lisibilité et la sécurité, même lorsque le projet prend de l'ampleur et attire davantage de contributeurs.

Comment le respect de ces règles améliore la maintenabilité, la sécurité et l'intégration

Le respect d'un ensemble clair de règles de revue de code a un impact direct sur la santé de votre projet :

  • Maintenabilité : Des structures de dossiers, des conventions de nommage et des modèles de codage cohérents facilitent la lecture, la navigation et l'extension de la base de code.
  • Sécurité : La validation des entrées, la désinfection, les vérifications de permissions et l'accès contrôlé aux bases de données réduisent les vulnérabilités et préviennent les fuites de données accidentelles.
  • Onboarding plus rapide : Des normes partagées, des utilitaires documentés et des exemples clairs aident les nouveaux contributeurs à comprendre rapidement le projet et à contribuer en toute confiance.

En appliquant ces règles, les équipes peuvent s'assurer que la base de code reste évolutive, fiable et sécurisée, même à mesure que le nombre de contributeurs augmente.

Relier le contexte aux règles

Avant d'examiner les règles, il est important de comprendre que maintenir une qualité de code élevée dans un projet tel que Strapi ne consiste pas seulement à suivre les meilleures pratiques générales. Il s'agit d'avoir des modèles et des normes clairs qui aident des centaines de contributeurs à rester sur la même longueur d'onde. Chacune des 20 règles ci-dessous se concentre sur les défis réels qui apparaissent dans la base de code de Strapi.

Les exemples fournis pour chaque règle illustrent des approches non conformes et conformes, offrant une image claire de la manière dont ces principes s'appliquent en pratique.

Explorons maintenant les règles qui rendent la base de code de Strapi évolutive, cohérente et de haute qualité, en commençant par la structure du projet et les standards de configuration.

Règles : Structure et cohérence du projet

1. Suivre les conventions de dossiers établies de Strapi

Évitez de disperser les fichiers ou d'inventer de nouvelles structures. Respectez l'organisation de projet établie de Strapi pour maintenir une navigation prévisible.

Exemple non conforme

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

Exemple conforme

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

2. Maintenir la cohérence des fichiers de configuration

Utilisez les mêmes conventions de structure, de nommage et de formatage dans tous les fichiers de configuration pour assurer la cohérence et prévenir les erreurs.

Exemple non conforme

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});

Exemple conforme

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. Maintenir une stricte sécurité de type

Tout code nouveau ou mis à jour doit inclure des types TypeScript précis ou des définitions JSDoc. Évitez d'utiliser `any`, les types de retour manquants ou l'inférence de type implicite dans les modules partagés.

Exemple non conforme

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

Exemple conforme

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. Nomenclature cohérente pour les services et les contrôleurs

Les noms des contrôleurs et des services doivent clairement correspondre à leur domaine (par exemple, user.controller.js avec user.service.js).

Exemple non conforme

1src/
2└── api/
3    └── user/
4        ├── controllers/
5        │ └── mainController.js
6        ├── services/
7        │ └── accountService.js
8        ├── routes/
9        │ └── utilisateur.js

Exemple conforme

1src/
2└── api/
3    └── user/
4        ├── controllers/
5        │ └── utilisateur.js
6        ├── services/
7        │ └── utilisateur.js
8        ├── routes/
9        │ └── utilisateur.js
10        └── content-types/
11            └── user/schéma.json

Règles : qualité et maintenabilité du code

5. Simplifier le flux de contrôle avec des retours anticipés

Au lieu d'imbrications profondes de if/else, retournez tôt lorsque les conditions échouent.

Exemple non conforme

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};

Exemple conforme

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. Éviter l'imbrication excessive dans les contrôleurs

Évitez les grands blocs de logique imbriquée dans les contrôleurs ou les services. Extrayez les conditions répétées ou complexes dans des fonctions d'aide ou des utilitaires bien nommés.

Exemple non conforme

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};

Exemple conforme

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. Maintenir la logique métier hors des contrôleurs

Les contrôleurs doivent rester légers et uniquement orchestrer les requêtes. Déplacez la logique métier vers les services.

Exemple non conforme

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};

Exemple conforme

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. Utiliser des fonctions utilitaires pour les motifs récurrents

Les motifs dupliqués (par exemple, validation, formatage) devraient résider dans des utilitaires partagés.

Exemple non conforme

// 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 } });
  },
};

Exemple conforme

// src/utils/slugify.js
module.exports = (texte) => 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. Supprimer les journaux de débogage avant la production

N'utilisez pas console.log, console.warn ou console.error dans le code de production. Utilisez toujours strapi.log ou un logger configuré pour vous assurer que les logs respectent les paramètres d'environnement et évitent d'exposer des informations sensibles.

Exemple non conforme

// 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;
  },
};

Exemple conforme

// 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);
}

Règles : Bases de données et pratiques de requête

10. Éviter les requêtes SQL brutes

N'exécutez pas de requêtes SQL brutes dans les contrôleurs ou les services. Utilisez toujours une méthode de requête cohérente et de haut niveau (comme un ORM ou un constructeur de requêtes) pour assurer la maintenabilité, appliquer les règles/hooks et réduire les risques de sécurité.

Exemple non conforme

// 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;
  },
};

Exemple conforme

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

11. Utiliser le moteur de requêtes de Strapi de manière cohérente

Ne mélangez pas différentes méthodes d'accès aux bases de données (par exemple, appels ORM vs requêtes brutes) au sein de la même fonctionnalité. Utilisez une approche de requête unique et cohérente pour assurer la maintenabilité, la lisibilité et un comportement prévisible.

Exemple non conforme

// 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 };
  },
};

Exemple conforme

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

12. Optimiser les appels de base de données

Regrouper les requêtes de base de données connexes ou les combiner en une seule opération pour éviter les goulots d'étranglement de performance et réduire les appels séquentiels inutiles.

Exemple non conforme

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;
}

Exemple conforme

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

Règles : API et Sécurité

13. Valider les entrées avec les validateurs Strapi

Ne faites jamais confiance aux entrées provenant de clients ou de sources externes. Validez toutes les données entrantes à l'aide d'un mécanisme de validation cohérent avant de les utiliser dans les contrôleurs, les services ou les opérations de base de données.

Exemple non conforme

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);
}

Exemple conforme

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. Nettoyer les entrées utilisateur avant de les enregistrer

Assainissez toutes les entrées avant de les enregistrer dans la base de données ou de les transmettre à d'autres systèmes.

Exemple non conforme

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);
}

Exemple conforme

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. Appliquer les vérifications de permissions

Appliquez des vérifications de permissions sur chaque route protégée pour garantir que seuls les utilisateurs autorisés peuvent y accéder.

Exemple non conforme

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 });
}

Exemple conforme

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. Gestion cohérente des erreurs avec Boom

Gérer les erreurs de manière cohérente sur toutes les routes d'API en utilisant un mécanisme de gestion des erreurs centralisé ou unifié.

Exemple non conforme

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
  }
}

Exemple conforme

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 };

Règles : Tests et documentation

17. Ajouter ou mettre à jour des tests pour chaque fonctionnalité

Le nouveau code sans tests ne sera pas fusionné, les tests font partie de la définition de « terminé ».

Exemple non conforme

// 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

Exemple conforme

// 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. Documenter les nouveaux endpoints

Tout ajout d'API doit être documenté dans la documentation de référence avant la fusion.

Exemple non conforme

// 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

Exemple conforme

// 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 };
  },
};

Exemple de mise à jour des documents de référence :

### POST /users/deactivate

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

Réponse :

{
  "success": true
}

Erreurs :

  • 400 : userId est requis
  • 404 : Utilisateur introuvable
Pourquoi cela fonctionne :  
- Les développeurs et les consommateurs d'API peuvent découvrir et utiliser les endpoints de manière fiable  
- Assure la cohérence entre l'implémentation et la documentation  
- Facilite la maintenance et l'intégration  

---

Voulez-vous que je continue avec la **Règle n°19 (« Utiliser JSDoc pour les utilitaires partagés »)** dans le même format ensuite ?

19. Utiliser JSDoc pour les utilitaires partagés

Les fonctions partagées devraient être expliquées avec JSDoc pour faciliter l'intégration et la collaboration.

Exemple non conforme

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

module.exports = slugify;

Exemple conforme

// 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. Mettre à jour le changelog à chaque PR significative

Mettez à jour le changelog du projet avec chaque fonctionnalité majeure, correction de bug ou modification d'API avant de fusionner une PR.

Exemple non conforme

# CHANGELOG.md

## [1.0.0] - 2025-09-01
- Version initiale

Exemple conforme

# CHANGELOG.md

## [1.1.0] - 2025-10-06
- Ajout du point de terminaison de désactivation d'utilisateur (`POST /users/deactivate`)
- Correction d'un bug dans la génération de slugs pour les titres d'articles
- Mise à jour du service de notification par e-mail pour gérer l'envoi par lots

Conclusion

Nous avons étudié le dépôt public de Strapi pour comprendre comment des modèles de code cohérents aident les grands projets open source à se développer sans perdre en qualité. Ces 20 règles ne sont pas théoriques. Ce sont des leçons pratiques tirées directement de la base de code de Strapi qui rendent le projet plus facile à maintenir, plus sécurisé et plus lisible.

Si votre projet prend de l'ampleur, retenez ces leçons et appliquez-les à vos revues de code. Elles vous aideront à passer moins de temps à nettoyer du code désordonné et plus de temps à développer des fonctionnalités qui comptent vraiment.

FAQ

Des questions ?

Pourquoi les règles de revue de code sont-elles importantes dans les projets open source comme Strapi ?

Étant donné que des centaines de développeurs contribuent, des règles de révision cohérentes évitent le chaos. Elles garantissent que chaque pull request suit la même structure, la même nomenclature et les mêmes modèles de sécurité, assurant ainsi la stabilité et la maintenabilité du projet sur le long terme.

Comment Strapi maintient-il la qualité du code à grande échelle ?

Strapi utilise des conventions de dossiers strictes, l'adoption de TypeScript, des tests automatisés et une validation standardisée. Chaque modification est examinée pour sa clarté, ses performances et sa sécurité avant d'être fusionnée.

Quelle est la différence entre le linting et les règles de revue de code ?

Le linting détecte automatiquement les problèmes de syntaxe et de formatage. Les règles de revue de code vont plus loin – elles abordent l'architecture, la lisibilité, la clarté des noms, la maintenabilité et la sécurité que les outils ne peuvent pas détecter sans un contexte humain ou de niveau IA.

Comment les équipes peuvent-elles appliquer ces règles à leurs propres projets ?

- Documentez vos normes de révision.
- Ajoutez des vérifications automatisées et des modèles de relations publiques.
- Utilisez des noms et des structures de dossiers cohérents.
- Appliquez des tests et des mises à jour de la documentation à chaque fusion.
- Utilisez des outils de révision de code basés sur l'IA, tels que Aikido Quality, pour détecter les problèmes de conception de haut niveau.

Quels outils peuvent aider à appliquer automatiquement les règles de revue de code ?

Des outils comme Aikido Security Code Quality aident à détecter les problèmes d'architecture, de maintenabilité et de sécurité lors des revues de code, allant bien au-delà du linting traditionnel.

Quel est le plus grand défi dans la maintenance de la base de code de Strapi ?

Équilibrer innovation et cohérence – les nouveaux contributeurs apportent de nouvelles idées, mais sans règles claires, le projet risque de diverger vers des modèles incohérents et un code difficile à maintenir.

Comment ces règles améliorent-elles l'intégration des nouveaux contributeurs ?

Elles offrent une feuille de route claire des attentes. Lorsque la structure des dossiers, le nommage et la documentation sont prévisibles, les nouveaux développeurs peuvent rapidement comprendre comment contribuer sans rompre les modèles existants.

Sécurisez-vous maintenant.

Sécuriser votre code, votre cloud et votre runtime dans un système centralisé unique.
Détectez et corrigez les vulnérabilités rapidement et automatiquement.

Pas de carte de crédit requise | Résultats du scan en 32 secondes.