Aikido

Strapi'nin kod tabanından ne öğrendik: Ölçeklenebilir geliştirme için 20 kod inceleme kuralı

Giriş

Strapi, en popüler açık kaynaklı headless CMS platformlarından biridir, ancak aynı zamanda yüzlerce katkıda bulunanı ve binlerce çekme isteği (pull request) barındıran devasa bir kod tabanıdır. Böyle büyük bir projenin kalitesini yüksek tutmak kolay değildir. Her katkının güvenilir, okunabilir ve güvenli kalmasını sağlamak için net ve tutarlı kod inceleme (code review) kuralları gerektirir.

Bu makalede, Strapi'nin genel (public) repository'sine dayanarak bir dizi kod inceleme kuralı derledik. Bu kurallar gerçek çalışmalardan doğmuştur: projenin büyümesine yardımcı olan ve kod tabanını kararlı tutan gerçek sorunlar, tartışmalar ve pull request'ler.

Büyük bir açık kaynaklı projede kod kalitesini korumak neden zordur?

Büyük bir açık kaynak projesinde kaliteyi korumak; katkıların muazzam ölçeği ve çeşitliliği nedeniyle zorlayıcıdır. Gönüllülerden kıdemli mühendislere kadar yüzlerce hatta binlerce geliştirici, her biri yeni özellikler, hata düzeltmeleri veya yeniden yapılandırmalar (refactors) içeren pull request'ler gönderir. Net kurallar olmadığında kod tabanı hızla tutarsız, kırılgan veya üzerinde çalışılması güç bir hale gelebilir.

Başlıca zorluklardan bazıları şunlardır:

  • Farklı deneyim seviyelerine sahip katılımcılar.
  • Modüller arasında tutarsız kodlama kalıpları (patterns).
  • Sinsi hatalar ve kod tabanına sızan mükerrer mantık (duplicated logic).
  • Güvenlik riskleri: Süreçlerin uygulanmaması durumunda ortaya çıkar.
  • Zaman alıcı incelemeler: Kod tabanının tamamına aşina olmayan gönüllüler için geçerlidir.

Bu zorlukların üstesinden gelmek için başarılı projeler yapılandırılmış süreçlere güvenir: paylaşılan standartlar, otomasyon araçları ve net yönergeler. Bu uygulamalar, proje büyüse ve daha fazla katkıda bulunan insanı kendine çekse bile sürdürülebilirliği, okunabilirliği ve güvenliği garanti eder.

Bu kurallara uymanın sürdürülebilirliği, güvenliği ve uyum sürecini nasıl iyileştirdiği

Net bir kod inceleme kuralları bütününe bağlı kalmak, projenizin sağlığı üzerinde doğrudan bir etkiye sahiptir:

  • Sürdürülebilirlik: Tutarlı klasör yapısı, adlandırma kuralları ve kodlama kalıpları, kod tabanının okunmasını, incelenmesini ve genişletilmesini kolaylaştırır.
  • Güvenlik: Giriş doğrulama, sanitizasyon, yetki kontrolleri ve denetimli veritabanı erişimi, güvenlik açıkları azaltır ve kazara veri sızıntılarını önler.
  • Daha Hızlı Uyum Süreci: Paylaşılan standartlar, belgelenmiş araçlar ve net örnekler, yeni katkıda bulunanların projeyi hızla kavramasına ve güvenle katkı sağlamasına yardımcı olur.

Ekipler bu kuralları uygulayarak, katkıda bulunanların sayısı artsa bile kod tabanının ölçeklenebilir, güvenilir ve güvenli kalmasını sağlayabilir.

Bağlamı kurallarla buluşturmak

Kurallara geçmeden önce, Strapi gibi bir projede kod kalitesini yüksek tutmanın yalnızca genel en iyi uygulamaları takip etmekten ibaret olmadığını anlamak önemlidir. Bu durum, yüzlerce katılımcının aynı sayfada kalmasını sağlayan net kalıplara ve standartlara sahip olmakla ilgilidir. Aşağıdaki 20 kuralın her biri, Strapi'nin kod tabanında ortaya çıkan gerçek zorluklara odaklanmaktadır.

Her kural için sağlanan örnekler, uyumlu olan ve olmayan yaklaşımları göstererek bu ilkelerin pratikte nasıl uygulandığına dair net bir tablo sunar.

Şimdi, proje yapısı ve yapılandırma standartlarından başlayarak Strapi'nin kod tabanını ölçeklenebilir, tutarlı ve yüksek kaliteli kural setini inceleyelim.

Kurallar: Proje yapısı ve tutarlılık

1. Strapi'nin belirlenmiş klasör kurallarına uyun

Dosyaları rastgele dağıtmaktan veya yeni yapılar icat etmekten kaçının. Gezinmeyi öngörülebilir tutmak için Strapi'nin belirlenmiş proje düzenine bağlı kalın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Yapılandırma dosyalarını tutarlı tutun

Tutarlılığı sağlamak ve hataları önlemek için tüm yapılandırma dosyalarında aynı yapıyı, adlandırmayı ve biçimlendirme kurallarını kullanın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Katı tip güvenliğini koruyun

Tüm yeni veya güncellenmiş kodlar doğru TypeScript tipleri veya JSDoc tanımlamaları içermelidir. Paylaşılan modüllerde any kullanmaktan, eksik dönüş tiplerinden veya örtük tip çıkarımından kaçının.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Servisler ve controller'lar için tutarlı adlandırma

Controller ve servis adları, alan adlarıyla açık bir şekilde eşleşmelidir (ör. user.controller.js ve user.service.js).

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

Kurallar: Kod kalitesi ve sürdürülebilirlik

5. Erken return (early return) kullanarak kontrol akışını sadeleştirin

Derin if/else iç içe yapıları (nesting) kullanmak yerine, koşullar sağlanmadığında işlemi erken sonlandırarak return edin.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Controller'larda aşırı iç içe yapılardan kaçının

Controller veya service katmanlarında büyük iç içe mantık blokları bulundurmaktan kaçının. Tekrar eden veya karmaşık koşulları, anlamlı isimlere sahip yardımcı fonksiyonlara (helper) ya da araçlara taşıyın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. İş mantığını (business logic) controller'ların dışında tutun

Controller'lar yalın kalmalı ve yalnızca istekleri yönetmelidir. İş mantığını service'lere taşıyın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Tekrar eden kalıplar için utility fonksiyonları kullanın

Tekrar eden kalıplar (ör. doğrulama, biçimlendirme) paylaşılan utility'lerde yer almalıdır.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

// src/utils/slugify.js
module.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. Prod ortamına geçmeden önce hata ayıklama (debugging) log'larını kaldırın

Canlı (production) kodunda console.log, console.warn veya console.error kullanmayın. Log'ların ortam ayarlarına uymasını ve hassas bilgilerin sızmasını önlemek için her zaman strapi.log veya yapılandırılmış bir logger kullanın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

Kurallar: Veritabanı ve sorgu pratikleri

10. Ham (raw) SQL sorgularından kaçının

Controller veya service'lerde ham SQL sorguları çalıştırmayın. Sürdürülebilirliği sağlamak, kuralları/hook'ları uygulamak ve güvenlik risklerini azaltmak için her zaman tutarlı, üst düzey bir sorgu yöntemi (ORM veya query builder gibi) kullanın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

11. Strapi'nin sorgu motorunu tutarlı bir şekilde kullanın

Aynı özellik içerisinde farklı veritabanı erişim yöntemlerini (ör. ORM çağrıları ile ham sorgular) bir arada kullanmayın. Sürdürülebilirliği, okunabilirliği ve öngörülebilir davranışları garanti etmek için tek ve tutarlı bir sorgu yaklaşımı benimseyin.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

12. Veritabanı çağrılarını optimize edin

Performans darboğazlarını önlemek ve gereksiz ardışık çağrıları azaltmak için ilgili veritabanı sorgularını toplu halde (batch) çalıştırın veya tek bir işlemde birleştirin.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

Kurallar: API ve Güvenlik

13. Girdileri Strapi validatörleri ile doğrulayın

İstemcilerden veya harici kaynaklardan gelen hiçbir girdiye körü körüne güvenmeyin. Controller, service veya veritabanı işlemlerinde kullanmadan önce tüm gelen verileri tutarlı bir doğrulama mekanizmasından geçirin.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Kullanıcı girdilerini kaydetmeden önce sanitize edin

Veritabanına kaydetmeden veya diğer sistemlere iletmeden önce tüm girdileri sanitize edin.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Yetki kontrollerini zorunlu kılın

Yalnızca yetkili kullanıcıların erişebilmesini sağlamak için korumalı her rotaya yetki kontrolü uygulayın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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. Boom ile tutarlı hata yönetimi

Merkezi veya birleştirilmiş bir hata yönetimi mekanizması kullanarak tüm API rotalarında hataları tutarlı bir şekilde ele alın.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

Kurallar: Test ve dokümantasyon

17. Her özellik için test ekleyin veya güncelleyin

Test edilmeyen yeni kodlar merge edilmez; testler "tamamlandı" tanımının bir parçasıdır.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

// 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. Yeni uç noktaları (endpoint) belgelendirin

Her API eklemesi, merge işleminden önce referans dokümanlarında belgelendirilmelidir.

❌ Uyumsuz örnek

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

✅ Kurala Uygun Örnek

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

Referans Dokümanı Güncelleme Örneği:

### POST /users/deactivate

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

Yanıt:

{
  "success": true
}

Hatalar:

  • 400: userId alanı zorunludur
  • 404: Kullanıcı bulunamadı
Neden işe yarıyor:  
- Geliştiriciler ve API tüketicileri uç noktaları güvenilir şekilde keşfedebilir ve kullanabilir  
- Uygulama ile dokümantasyon arasında tutarlılık sağlar  
- Bakım ve ekibe adaptasyon (onboarding) süreçlerini kolaylaştırır  

---

Bir sonraki aşamada **#19 numaralı kural (“Paylaşılan Yardımcı Araçlar İçin JSDoc Kullanın”)** ile aynı formatta devam etmemi ister misiniz?

19. Paylaşılan yardımcı araçlar için JSDoc kullanın

Ekibe adaptasyonu ve iş birliğini kolaylaştırmak için paylaşılan fonksiyonlar JSDoc ile açıklanmalıdır.

❌ Uyumsuz örnek

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

module.exports = slugify;

✅ Kurala Uygun Örnek

// 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. Önemli her PR ile birlikte değişiklik günlüğünü (changelog) güncelleyin

Bir PR merge edilmeden önce projenin değişiklik günlüğünü (changelog) her önemli özellik, hata düzeltmesi veya API değişikliği ile güncelleyin.

❌ Uyumsuz örnek

# CHANGELOG.md

## [1.0.0] - 2025-09-01
- İlk sürüm

✅ Kurala Uygun Örnek

# CHANGELOG.md

## [1.1.0] - 2025-10-06
- Kullanıcı devre dışı bırakma uç noktası eklendi (`POST /users/deactivate`)
- Makale başlıkları için slug oluşturmadaki bir hata giderildi
- Toplu gönderimleri yönetecek şekilde e-posta bildirim servisi güncellendi

Sonuç

Tutarlı kod kalıplarının büyük açık kaynaklı projelerin kaliteden ödün vermeden büyümesine nasıl yardımcı olduğunu anlamak için Strapi'nin resmi deposunu inceledik. Bu 20 kural birer teoriden ibaret değil. Doğrudan Strapi'nin kod tabanından alınan ve projeyi bakımı daha kolay, daha güvenli ve okunabilir kılan pratik derslerdir.

Projeniz büyüyorsa bu dersleri alın ve kod incelemelerinize (code review) uygulayın. Düzensiz kodları temizlemekle daha az, gerçekten önem taşıyan özellikler geliştirmekle daha çok zaman geçirmenize yardımcı olacaktır.

Sık Sorulan Sorular

Sorularınız mı var?

Strapi gibi açık kaynaklı projelerde kod inceleme (code review) kuralları neden önemlidir?

Yüzlerce geliştirici katkıda bulunduğu için tutarlı inceleme kuralları kaosu önler. Her bir pull request'in aynı yapıyı, isimlendirmeyi ve güvenlik kalıplarını takip etmesini sağlayarak projenin zaman içinde kararlı ve sürdürülebilir kalmasını garantiler.

Strapi, kod kalitesini ölçeklenebilir bir şekilde nasıl koruyor?

Strapi; katı klasör kuralları, TypeScript benimsemesi, otomatik testler ve standartlaştırılmış doğrulama süreçleri kullanır. Her değişiklik, birleştirilmeden (merge) önce netlik, performans ve güvenlik açısından incelenir.

Linting ile kod inceleme kuralları arasındaki fark nedir?

Linting, sözdizimi ve biçimlendirme sorunlarını otomatik olarak yakalar. Kod inceleme kuralları ise daha derinlere inerek; araçların insan veya yapay zeka düzeyinde bağlam olmadan algılayamayacağı mimari, okunabilirlik, isimlendirme netliği, sürdürülebilirlik ve güvenlik konularını ele alır.

Ekipler bu kuralları kendi projelerine nasıl uygulayabilir?

- İnceleme standartlarınızı belgelendirin.
- Otomatik kontroller ve PR şablonları ekleyin.
- Tutarlı isimlendirme ve klasör yapıları kullanın.
- Her bir merge işleminde testleri ve dokümantasyon güncellemelerini zorunlu kılın.
- Üst düzey tasarım sorunlarını yakalamak için Aikido Code Quality gibi yapay zeka tabanlı kod inceleme araçları kullanın.

Kod inceleme kurallarının otomatik olarak uygulanmasına hangi araçlar yardımcı olabilir?

Aikido Security Code Quality gibi araçlar, kod incelemeleri sırasında mimari, sürdürülebilirlik ve güvenlik sorunlarının tespit edilmesine yardımcı olur; geleneksel linting araçlarının çok ötesine geçer.

Strapi'nin kod tabanını korurken karşılaşılan en büyük zorluk nedir?

Yenilik ile tutarlılığı dengelemek; yeni katkıda bulunanlar taze fikirler getirir, ancak net kurallar olmadığında proje, tutarsız kalıplara ve bakımı zor kodlara dönüşme riski taşır.

Bu kurallar, yeni katkıda bulunanların projeye adapte sürecini (onboarding) nasıl iyileştirir?

Beklentilere dair net bir yol haritası sunarlar. Klasör yapısı, isimlendirme ve dokümantasyon öngörülebilir olduğunda, yeni geliştiriciler mevcut yapıları bozmadan nasıl katkıda bulunabileceklerini hızlıca anlayabilirler.

Şimdi güvenliğinizi sağlayın

Kodunuzu, bulutunuzu ve çalışma zamanınızı tek bir merkezi sistemde güvenceye alın.
Güvenlik açıklarını otomatik olarak hızla bulun ve düzeltin.

Kredi kartı gerekmez | Tarama sonuçları 32 saniyede.