Giriş
Grafana, GitHub'da 70 binden fazla yıldıza ve her gün onu geliştiren binlerce katkıda bulunan kişiye sahip, en popüler açık kaynaklı izlenebilirlik (observability) platformlarından biridir. Sürekli hareket halinde olan 3 binden fazla açık sorun (issue) ve yüzlerce pull request ile kod tabanını temiz ve tutarlı tutmak gerçek bir meydan okumadır.
Kod tabanını inceleyerek, ekibin hız kesmeden yüksek kaliteyi korumasına yardımcı olan yazılmamış kurallardan ve en iyi uygulamalardan bazılarını ortaya çıkarabiliriz. Bu kuralların birçoğu güvenliğe, sürdürülebilirliğe ve güvenilirliğe odaklanır. Bazıları ise uygunsuz async kullanımı, kaynak sızıntıları veya kod genelindeki tutarsız desenler gibi geleneksel statik analiz araçlarının (SAST) yakalayamadığı sorunlarla ilgilidir. Bunlar, insan incelemecilerin veya yapay zeka destekli araçların bir kod incelemesi sırasında fark edebileceği türden sorunlardır.
Zorluklar
Bunun gibi büyük projeler çeşitli zorluklarla karşı karşıyadır: devasa kod hacmi, çok sayıda modül (API, UI, eklentiler) ve sayısız dış entegrasyon (Prometheus, Loki vb.). Yüzlerce katkıda bulunan kişi farklı kodlama stilleri veya varsayımları izliyor olabilir. Yeni özellikler ve hızlı düzeltmeler gizli hatalara (bugs), güvenlik açıkları (flaws) veya kafa karıştırıcı kod yollarına yol açabilir. Gönüllü incelemeciler kod tabanının her parçasını bilmeyebilir, bu da kaçırılan tasarım kalıplarına veya en iyi uygulamalara yol açabilir. Kısacası, ölçek ve katkıların çeşitliliği tutarlılığı ve güvenilirliği sağlamayı zorlaştırır.
Bu kuralların önemi nedir?
Net bir inceleme kuralları seti, doğrudan Grafana'nın sağlığına katkıda bulunur. İlk olarak, sürdürülebilirlik gelişir: tutarlı kalıplar (klasör düzeni, adlandırma, hata yönetimi) kodun okunmasını, test edilmesini ve genişletilmesini kolaylaştırır. Herkes ortak kurallara u когатоda incelemeciler niyet tahmin etmeye daha az zaman harcar. İkinci olarak, güvenlik artırılır: "her zaman kullanıcı girişini doğrula" veya "açık yönlendirmelerden (open redirects) kaçın" gibi kurallar, Grafana'da daha önce bulunmuş güvenlik açıkları (CVE-2025-6023/4123 vb.) önler. Son olarak, yeni katkıda bulunanların oryantasyonu daha hızlı gerçekleşir: örnekler ve incelemeler sürekli olarak aynı uygulamaları kullandığında, yeni gelenler "Grafana yolunu" hızlı ve özgüvenli bir şekilde öğrenirler.
Bu kurallara bağlam oluşturmak
Bu kurallar Grafana'nın kodundaki ve topluluğundaki gerçek sorunlardan kaynaklanmaktadır. Güvenlik uyarıları ve hata raporları, önleyici kurallara dönüştürdüğümüz kalıpları (ör. XSS'e yol açan path traversal) ortaya çıkarıvermiştir. Aşağıdaki her kural somut bir tuzağı vurgular, neden önemli olduğunu açıklar (performans, netlik, güvenlik vb.) ve Grafana'nın dillerinde (Go veya TypeScript/JS) net bir ❌ kurala uymayan ile ✅ kurala uyan kod parçacığı gösterir.
Şimdi Grafana'nın kod tabanını sağlam, güvenli ve anlaşılır tutmaya yardımcı olan 10 kuralı keşfedelim.
Grafana'dan İlham Alan 10 Pratik Kod Kalitesi Kuralı
1. Yapılandırma için çevre değişkenleri (environment variables) kullanın (sabit kodlanmış değerlerden kaçının).
Portları, kimlik bilgilerini, URL'leri veya ortama özel diğer değerleri kodun içine sabit olarak yazmaktan (hard-coding) kaçının. Kodu esnek tutmak ve gizli bilgileri (secrets) kaynak koddan uzak tutmak için bunları çevre değişkenlerinden veya yapılandırma dosyalarından okuyun.
❌ Uyumsuz:
// server.js
const appPort = 3000;
app.listen(appPort, () => console.log("Listening on port " + appPort));✅ Uyumlu:
// server.ts
const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));Neden önemli?: Çevre değişkenleri kullanmak, hassas verileri kaynak kodun dışında tutar, farklı ortamlar arasında dağıtımları esnek hale getirir ve gizli bilgilerin kazara sızdırılmasını önler. Ayrıca yapılandırma değişikliklerinin kod üzerinde değişiklik yapılmasını gerektirmemesini sağlayarak sürdürülebilirliği artırır ve hataları azaltır.
2. Kullanıcı girdilerini kullanmadan önce sanitize edin.
Enjeksiyon (injection) saldırılarını ve beklenmeyen davranışları önlemek için kullanıcılardan veya harici kaynaklardan gelen tüm girdiler, kullanılmadan önce doğrulanmalı veya sanitize edilmelidir.
❌ Uyumsuz:
// frontend/src/components/UserForm.tsx
const handleSubmit = (username: string) => {
setUsers([...users, { name: username }]);
};✅ Uyumlu:
// frontend/src/utils/sanitize.ts
export function sanitizeInput(input: string): string {
return input.replace(/<[^>]*>/g, ''); // removes HTML tags
}
// frontend/src/components/UserForm.tsx
import { sanitizeInput } from '../utils/sanitize';
const handleSubmit = (username: string) => {
const cleanName = sanitizeInput(username);
setUsers([...users, { name: cleanName }]);
};Neden önemli?: Doğru girdi sanitizasyonu; XSS, enjeksiyon saldırıları ve hatalı biçimlendirilmiş girdilerden kaynaklanan beklenmeyen davranışları engeller. Hem kullanıcıları hem de sistemi korur ve alt süreçlerin, günlük kaydının (logging) ve depolamanın verileri güvenli bir şekilde işlemesini sağlar.
3. Açık yönlendirmeleri (open redirects) ve yol geçişini (path traversal) önleyin.
Kodunuzda kullanılan tüm URL'lerin veya dosya yollarının uygun şekilde doğrulandığından ve sanitize edildiğinden emin olun. Kullanıcı girdilerinin yönlendirmeleri veya dosya sistemi yollarını doğrudan belirlemesine izin vermeyin.
❌ Uyumsuz:
// Express route in Grafana plugin
app.get("/goto", (req, res) => {
const dest = req.query.next; // attacker can supply any URL
res.redirect(dest);
});✅ Uyumlu:
// Express route with safe redirect
app.get("/goto", (req, res) => {
const dest = req.query.next;
// Only allow relative paths starting with '/'
if (dest && dest.startsWith("/")) {
res.redirect(dest);
} else {
res.status(400).send("Invalid redirect URL");
}
});Neden önemli?: Açık yönlendirmeleri ve yol geçişini önlemek; kullanıcıları kimlik avından (phishing), veri sızıntılarından ve yetkisiz dosya erişiminden korur. Saldırı yüzeyini daraltır, güvenlik sınırlarını uygular ve hassas sunucu kaynaklarının kazara açığa çıkmasını önler.
4. Katı bir içerik güvenlik politikası (CSP) etkinleştirin.
Uygulama başlıklarında (headers), yalnızca güvenilir kaynaklardan gelen betiklere (script), stillere, görsellere ve diğer kaynaklara izin veren bir İçerik Güvenlik Politikası (Content Security Policy) uygulayın. Güvenli olmayan satır içi (unsafe-inline), eval ve joker (wildcard) kaynaklara izin vermeyin.
❌ Uyumsuz: (CSP yok veya çok esnek)
# grafana.ini (uyumsuz)
content_security_policy = false✅ Uyumlu: (Yapılandırmada güçlü CSP)
# grafana.ini
content_security_policy = true
content_security_policy_template = """
script-src 'self' 'unsafe-eval' 'unsafe-inline' 'strict-dynamic' $NONCE;
object-src 'none';
font-src 'self';
style-src 'self' 'unsafe-inline' blob:;
img-src * data:;
base-uri 'self';
connect-src 'self' grafana.com ws://$ROOT_PATH wss://$ROOT_PATH;
manifest-src 'self';
media-src 'none';
form-action 'self';
"""Neden önemli?: Katı bir CSP, XSS dahil olmak üzere birçok taraflı (client-side) saldırı sınıfını engeller. Kaynaklar için öngörülebilir davranışlar sağlar, kötü amaçlı kod çalıştırılma olasılığını azaltır ve tarayıcı bağlamında net bir güvenlik sınırı çizer.
5. Hataları ve nil (boş) kontrollerini yönetin (paniklerden kaçının).
Fonksiyon çağrılarında, API yanıtlarında ve veri yapılarında her zaman hataları ve nil değerleri kontrol edin. Panik durumlarını uygun hata yönetimiyle değiştirin ve anlamlı hata mesajları veya kodları döndürün.
❌ Uyumsuz:
rows, _ := db.Query("SELECT * FROM users WHERE id=?", id) // ignored error
user := &User{}
rows.Next()
rows.Scan(&user.Name) // rows might be empty => user is nil => panic✅ Uyumlu:
rows, err := db.Query("SELECT * FROM users WHERE id=?", id)
if err != nil {
return nil, err
}
defer rows.Close()
if !rows.Next() {
return nil, errors.New("user not found")
}
var name string
if err := rows.Scan(&name); err != nil {
return nil, err
}
user := &User{Name: name}Neden önemli?: Düzgün hata yönetimi çökmeleri önler ve beklenmeyen girdiler veya koşullar oluştuğunda bile sistemin kararlı kalmasını sağlar. Sürdürülebilirliği artırır, kesinti süresini (downtime) azaltır ve anlamlı hata bilgileri sağlayarak hata ayıklamayı (debugging) kolaylaştırır.
6. Kaynak temizliğini erteleyin (defer) (sızıntıları önleyin).
Dosyalar, ağ bağlantıları veya veritabanı tutamaçları gibi açılan tüm kaynakların, tahsis edildikten hemen sonra defer kullanılarak düzgün bir şekilde kapatıldığından emin olun. Kodun ilerleyen kısımlarında manuel temizleme işlemine güvenmeyin.
❌ Uyumsuz:
resp, err := http.Get(url)
// ... resp.Body kullan ...
// unuttun: resp.Body.Close()✅ Uyumlu:
resp, err := http.Get(url)
if err != nil {
// handle error
}
defer resp.Body.Close()
// ... use resp.Body ...Neden önemli?: Doğru kaynak temizliği; bellek sızıntılarını, dosya tanımlayıcı tükenmelerini ve bağlantı havuzu şişmelerini önler. Bu, sistem kararlılığını korur, zamanla performans düşüşünü engeller ve prod ortamındaki operasyonel sorunları azaltır.
7. Parametreli sorgular kullanın (SQL enjeksiyonundan kaçının).
SQL komutları için string birleştirme yerine, veritabanıyla etkileşime geçerken her zaman parametreli sorgular veya hazırlanan ifadeler (prepared statements) kullanın.
❌ Uyumsuz:
// Tehlikeli: userID bir SQL tırnağı veya enjeksiyonu içerebilir
query := "DELETE FROM sessions WHERE user_id = '" + userID + "';"
db.Exec(query)✅ Uyumlu:
// Güvenli: userID parametre olarak aktarılıyor
db.Exec("DELETE FROM sessions WHERE user_id = ?", userID)Neden önemli?: Parametreli sorgular, en yaygın güvenlik açıklarından biri olan SQL enjeksiyonu saldırılarını önler. Hassas verileri korur, veritabanı bozulması riskini azaltır ve sorguların bakımını ile denetlenmesini kolaylaştırır. Bu, uygulamanızın hem güvenliğini hem de güvenilirliğini garanti altına alır.
8. TypeScript'te async/await'i doğru kullanın (promise'leri yönetin).
Reddedilmeleri (rejections) göz ardı etmek veya callback tarzı kullanımı karıştırmak yerine, her zaman promise'leri bekleyin (await) ve try/catch kullanarak hataları yönetin.
❌ Uyumsuz:
async function fetchData() {
// Missing await: fetch returns a Promise, not the actual data
const res = fetch('/api/values');
console.log(res.data); // undefined
}✅ Uyumlu:
async function fetchData() {
try {
const res = await fetch('/api/values');
const data = await res.json();
console.log(data);
} catch (err) {
console.error("Fetch failed:", err);
}
}Neden önemli?: Doğru asenkron yönetimi; asenkron kodlardaki hataların gözden kaçmamasını sağlar, işlenmemiş promise reddetmelerini önler ve öngörülebilir bir program akışı korur. Kodu daha okunabilir ve hata ayıklaması daha kolay hale getirir; ayrıca veri bozulmasına, tutarsız durumlara veya beklenmeyen çalışma zamanı çökmelerine yol açabilecek ince hataları engeller.
9. TypeScript'te katı tipleri tercih edin ('any' kullanımından kaçının).
Değişkenleri, fonksiyon parametrelerini ve dönüş tiplerini tanımlamak için 'any' yerine hassas TypeScript tipleri kullanın.
❌ Uyumsuz:
// No types specified
function updateUser(data) {
// ...
}
let config: any = loadConfig();✅ Uyumlu:
interface User { id: number; name: string; }
function updateUser(data: User): Promise<User> {
// ...
}
interface AppConfig { endpoint: string; timeoutMs: number; }
const config: AppConfig = loadConfig();Neden önemli?: Katı tip kullanımı, derleme zamanında tiple ilgili hataları yakalayarak çalışma zamanı hatalarını azaltır ve kod güvenilirliğini artırır. Kodu kendi kendine dokümante olur hale getirir, yeniden yapılandırmayı (refactoring) kolaylaştırır ve sistemin tüm parçalarının öngörülebilir ve tip açısından güvenli bir şekilde etkileşime girmesini sağlar; bu da Grafana'nınki gibi büyük ve karmaşık kod tabanlarında çok önemlidir.
10. Tutarlı kod stili ve isimlendirme uygulayın.
Kod tabanı genelinde tekdüze biçimlendirme, isimlendirme kuralları ve dosya yapıları uygulayın.
❌ Uyumsuz: (karışık stiller)
const ApiData = await getdata(); // PascalCase for variable? function name not camelCase.
function Fetch_User() { ... } // Unusual naming.✅ Uyumlu:
const apiData = await fetchData();
function fetchUser() { ... }Neden önemli?: Tutarlı stil ve isimlendirme, okunabilirliği artırır ve birden fazla geliştiricinin kodu anlamasını ve bakımını yapmasını kolaylaştırır. Projede gezinirken oluşan bilişsel yükü azaltır, yanlış anlamalardan kaynaklanan gizli hataları önler ve otomatik araçların (linter'lar, biçimlendiriciler, kod inceleyicileri) büyük bir ekip ortamında kalite standartlarını güvenilir bir şekilde uygulayabilmesini sağlar.
Sonuç
Yukarıdaki kuralların her biri, Grafana'nın kod tabanındaki yinelenen bir zorluğa değinmektedir. Bunları kod incelemeleri sırasında tutarlı bir şekilde uygulamak; ekibin temiz ve öngörülebilir kod sürdürmesine, yaygın güvenlik açıkları önlenerek güvenliğin artırılmasına ve yeni katkıda bulunanlar için net kalıplar sunarak adaptasyon sürecinin (onboarding) pürüzsüzleştirilmesine yardımcı olur. Proje büyüdükçe bu uygulamalar, kod tabanının güvenilir, sürdürülebilir ve ilgili herkes için anlaşılması kolay kalmasını sağlar. Bu kuralları takip etmek, herhangi bir mühendislik ekibinin ölçeklenebilir ve yüksek kaliteli yazılımlar oluşturmasına ve sürdürmesine yardımcı olabilir.

