Giriş
Grafana, 70 binin üzerinde GitHub yıldızı ve her gün onu geliştiren binlerce katkıcıyla en popüler açık kaynaklı gözlemlenebilirlik platformlarından biridir. 3 binin üzerinde açık sorun ve sürekli olarak işleme alınan yüzlerce çekme isteği göz önüne alındığında, kod tabanını temiz ve tutarlı tutmak gerçek bir zorluktur.
Kod tabanını inceleyerek, ekibin hızlı ilerlerken kaliteyi yüksek tutmasına yardımcı olan bazı yazılı olmayan kuralları ve en iyi uygulamaları ortaya çıkarabiliriz. Bu kuralların çoğu güvenlik, bakım kolaylığı ve güvenilirliğe odaklanmaktadır. Bunlardan bazıları, geleneksel statik analiz araçlarının (SAST) tespit edemediği sorunlarla ilgilidir; örneğin, asenkron kullanım hataları, kaynak sızıntıları veya kod genelinde tutarsız kalıplar gibi. Bunlar, kod incelemesi sırasında insan denetçiler veya yapay zeka destekli araçların tespit 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, kullanıcı arayüzü, eklentiler) ve sayısız harici entegrasyon (Prometheus, Loki vb.). Yüzlerce katkıcı, farklı kodlama stilleri veya varsayımları takip edebilir. Yeni özellikler ve hızlı düzeltmeler, gizli hatalara, güvenlik açıklarına veya kafa karıştırıcı kod yollarına yol açabilir. Gönüllü gözden geçirenler, kod tabanının her bölümünü bilmeyebilir; bu da tasarım kalıplarının veya en iyi uygulamaların gözden kaçmasına neden olabilir. Kısacası, katkının ölçeği ve çeşitliliği, tutarlılık ve güvenilirliği sağlamayı zorlaştırır.
Bu kuralların önemi nedir?
Net bir inceleme kuralları seti, Grafana’nın sağlığına doğrudan fayda sağlar. İlk olarak, bakım kolaylığı artar: tutarlı kalıplar (klasör yapısı, adlandırma, hata işleme) kodun okunmasını, test edilmesini ve genişletilmesini kolaylaştırır. Herkes ortak kurallara uyduğunda, inceleme yapanlar niyeti tahmin etmek için daha az zaman harcar. İkincisi, güvenlik artar: “kullanıcı girdilerini her zaman doğrula” veya “açık yönlendirmelerden kaçın” gibi kurallar, Grafana’da tespit edilen güvenlik açıklarını (CVE-2025-6023/4123 vb.) önler. Son olarak, yeni katkıcıların sisteme entegrasyonu daha hızlı gerçekleşir: örnekler ve incelemelerde tutarlı bir şekilde aynı uygulamalar kullanıldığında, yeni gelenler “Grafana tarzını” hızlı ve kendinden emin bir şekilde öğrenir.
Bu kurallarla bağlam arasında bağlantı kurma
Bu kurallar, Grafana’nın kodunda ve topluluğunda karşılaşılan gerçek sorunlardan kaynaklanmaktadır. Güvenlik uyarıları ve hata raporları, önleyici kurallara dönüştürdüğümüz bazı kalıpları (örneğin, XSS'ye yol açan yol geçişi) ortaya çıkarmıştır. Aşağıdaki her kural, somut bir tuzağı vurgular, bunun neden önemli olduğunu (performans, netlik, güvenlik vb.) açıklar ve Grafana'nın dillerinde (Go veya TypeScript/JS) ❌ kurallara uymayan ile ✅ kurallara uyan kod parçacıklarını net bir şekilde gösterir.
Şimdi, Grafana’nın kod tabanını sağlam, güvenli ve anlaşılır tutmaya yardımcı olan 10 kuralı inceleyelim.
Grafana’dan İlham Alınan 10 Pratik Kod Kalitesi Kuralı
1. Yapılandırma için ortam değişkenlerini kullanın (sabit kodlanmış değerlerden kaçının).
Bağlantı noktalarını, kimlik bilgilerini, URL’leri veya diğer ortama özgü değerleri koda sabit olarak yazmaktan kaçının. Kodun esnekliğini korumak ve gizli bilgileri kaynak koddan uzak tutmak için bunları ortam değişkenlerinden veya yapılandırma dosyalarından okuyun.
❌ Uygun değil:
// server.js
const appPort = 3000;
app.listen(appPort, () => console.log("Port " + appPort));✅ Uygunluk:
// server.ts
const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => console.log(`Listening on port ${PORT}`));Bunun önemi: Çevre değişkenlerini kullanmak, hassas verilerin kaynak kodda yer almasını önler, farklı ortamlarda dağıtımları esnek hale getirir ve gizli bilgilerin kazara sızmasını engeller. Ayrıca, yapılandırma değişiklikleri için kodda değişiklik yapılmasına gerek kalmamasını sağlayarak bakım kolaylığını artırır ve hataları azaltır.
2. Kullanıcı girdisini kullanmadan önce temizleyin.
Enjeksiyon saldırılarını ve beklenmedik davranışları önlemek için, kullanıcılardan veya harici kaynaklardan gelen tüm girdiler kullanılmadan önce doğrulanmalı veya temizlenmelidir.
❌ Uygun değil:
// frontend/src/components/UserForm.tsx
const handleSubmit = (username: string) => {
setUsers([...users, { name: username }]);
};✅ Uygunluk:
// 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 }]);
};Bunun önemi: Giriş verilerinin uygun şekilde temizlenmesi, XSS, enjeksiyon saldırıları ve hatalı biçimlendirilmiş giriş verilerinin neden olduğu beklenmedik davranışları önler. Hem kullanıcıları hem de sistemi korur ve sonraki işlemlerin, günlük kaydının ve depolamanın verileri güvenli bir şekilde işlemesini sağlar.
3. Açık yönlendirmeleri ve yol geçişini önleyin.
Kodunuzda kullanılan tüm URL’lerin veya dosya yollarının uygun şekilde doğrulanıp temizlendiğinden emin olun. Kullanıcı girdilerinin yönlendirmeleri veya dosya sistemi yollarını doğrudan belirlemesine izin vermeyin.
❌ Uygun değil:
// Express route in Grafana plugin
app.get("/goto", (req, res) => {
const dest = req.query.next; // attacker can supply any URL
res.redirect(dest);
});✅ Uygunluk:
// 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");
}
});Bunun önemi: Açık yönlendirmeleri ve yol geçişini önlemek, kullanıcıları kimlik avı, veri sızıntıları ve yetkisiz dosya erişiminden korur. Saldırı yüzeyini azaltır, güvenlik sınırlarını güçlendirir ve hassas sunucu kaynaklarının kazara ifşa edilmesini önler.
4. Sıkı bir içerik güvenlik politikası (CSP) etkinleştirin.
Uygulama başlıklarında, yalnızca güvenilir kaynaklardan gelen komut dosyalarını, stil dosyalarını, resimleri ve diğer kaynaklara izin veren bir İçerik Güvenlik Politikası uygulayın. unsafe-inline, eval ve joker karakter içeren kaynaklara izin vermeyin.
❌ Uygun değil: (CSP yok veya çok gevşek)
# grafana.ini (uygun değil)
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';
"""Bunun önemi: Sıkı bir CSP, XSS dahil olmak üzere birçok türde istemci tarafı saldırısını engeller. Kaynaklar için öngörülebilir bir davranış sağlar, kötü amaçlı kodun çalıştırılma olasılığını azaltır ve tarayıcı bağlamında net bir güvenlik sınırı oluşturur.
5. Hataları ve nil denetimlerini işleyin (panik durumlarından kaçının).
İşlev ç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 işleme yöntemleriyle değiştirin ve anlamlı hata mesajları veya kodları döndürün.
❌ Uygun değil:
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✅ Uygunluk:
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}Bunun önemi: Doğru hata yönetimi, çökmeleri önler ve beklenmedik girdiler veya koşullar ortaya çıktığında bile sistemin güvenilirliğini korur. Anlamlı hata bilgileri sağlayarak bakım kolaylığını artırır, kesinti sürelerini azaltır ve hata ayıklamayı kolaylaştırır.
6. Kaynak temizleme işlemini erteleyin (sızıntıları önleyin).
Dosyalar, ağ bağlantıları veya veritabanı tanıtıcıları gibi açılmış 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şlemlerine güvenmeyin.
❌ Uygun değil:
resp, err := http.Get(url)
// ... resp.Body'yi kullan ...
// unutuldu: resp.Body.Close()✅ Uygunluk:
resp, err := http.Get(url)
if err != nil {
// handle error
}
defer resp.Body.Close()
// ... use resp.Body ...Bunun önemi: Doğru temizlik işlemleri, bellek sızıntılarını, dosya tanımlayıcılarının tükenmesini ve bağlantı havuzunun dolmasını önler. Bu, sistemin kararlılığını korur, zamanla performans düşüşünü önler ve üretim ortamındaki operasyonel sorunları azaltır.
7. Parametreli sorgular kullanın (SQL enjeksiyonunu önleyin).
Veritabanıyla etkileşim kurarken, SQL komutları için dize birleştirme yerine daima parametreli sorgular veya hazır ifadeler kullanın.
❌ Uygun değil:
// Tehlikeli: userID, SQL tırnak işareti veya enjeksiyon içerebilir
sorgu := "DELETE FROM sessions WHERE user_id = '" + userID + "';"
db.Exec(sorgu)✅ Uygunluk:
// Güvenli: userID parametre olarak aktarılır
db.Exec("DELETE FROM sessions WHERE user_id = ?", userID)Bunun önemi: Parametreli sorgular, en yaygın güvenlik açıklarından biri olan SQL enjeksiyon saldırılarını önler. Hassas verileri korur, veritabanının bozulma riskini azaltır ve sorguların bakımını kolaylaştırır, denetlenmesini kolaylaştırır. Bu, uygulamanızın hem güvenliğini hem de güvenilirliğini sağlar.
8. TypeScript'te async/await'i doğru şekilde kullanın (promise'ları işleyin).
Reddedilmeleri görmezden gelmek veya geri arama tarzı işleme yöntemlerini karıştırmak yerine, her zamanvaatleri bekleyin ve hataları try/catch kullanarak işleyin.
❌ Uygun değil:
async function fetchData() {
// Missing await: fetch returns a Promise, not the actual data
const res = fetch('/api/values');
console.log(res.data); // undefined
}✅ Uygunluk:
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);
}
}Bunun önemi: Doğru asenkron işleme, asenkron koddaki hataların gözden kaçmamasını sağlar, işlenmemiş promise reddetmelerini önler ve program akışının öngörülebilirliğini korur. Bu, kodu daha okunabilir ve hata ayıklaması daha kolay hale getirir; ayrıca veri bozulmasına, tutarsız duruma veya beklenmedik çalışma zamanı çökmelerine yol açabilecek ince hataları önler.
9. TypeScript’te katı tiplerden yana olun (herhangi birinden kaçının).
Değişkenleri, işlev parametrelerini ve dönüş türlerini tanımlarken “any” yerine kesin TypeScript türleri kullanın.
❌ Uygun değil:
// No types specified
function updateUser(data) {
// ...
}
let config: any = loadConfig();✅ Uygunluk:
interface User { id: number; name: string; }
function updateUser(data: User): Promise<User> {
// ...
}
interface AppConfig { endpoint: string; timeoutMs: number; }
const config: AppConfig = loadConfig();Bunun önemi: Sıkı tip denetimi, derleme aşamasında tip ile ilgili hataları yakalayarak çalışma zamanı hatalarını azaltır ve kodun güvenilirliğini artırır. Bu, kodun kendi kendini belgelemesini sağlar, yeniden yapılandırılmasını kolaylaştırır ve sistemin tüm parçalarının öngörülebilir, tip açısından güvenli bir şekilde etkileşime girmesini garanti eder; bu da Grafana gibi büyük ve karmaşık kod tabanlarında hayati önem taşır.
10. Kod stilinde ve isimlendirmede tutarlılık sağlayın.
Kod tabanının tamamında tek tip biçimlendirme, adlandırma kuralları ve dosya yapılarını uygulayın.
❌ Kurallara uymayan: (karışık stiller)
const ApiData = await getdata(); // PascalCase for variable? function name not camelCase.
function Fetch_User() { ... } // Unusual naming.✅ Uygunluk:
const apiData = await fetchData();
function fetchUser() { ... }Bunun önemi: Tutarlı stil ve adlandırma, okunabilirliği artırır ve birden fazla katkıcı için kodu anlamayı ve bakımını yapmayı kolaylaştırır. Proje içinde gezinirken zihinsel yükü azaltır, yanlış anlamalardan kaynaklanan ince hataları önler ve otomatik araçların (linter'lar, biçimlendiriciler, kod denetleyiciler) büyük bir ekip ortamında kalite standartlarını güvenilir bir şekilde uygulayabilmesini sağlar.
Sonuç
Yukarıdaki her kural, Grafana’nın kod tabanında sıkça karşılaşılan bir sorunu ele almaktadır. Kod incelemeleri sırasında bu kuralların tutarlı bir şekilde uygulanması, ekibin temiz ve öngörülebilir bir kod yapısını korumasına, yaygın güvenlik açıklarını önleyerek güvenliği artırmasına ve yeni katkıcılar için net şablonlar sunarak işe alım sürecini daha sorunsuz hale getirmesine yardımcı olur. Proje büyüdükçe, bu uygulamalar kod tabanını güvenilir ve bakımı kolay tutar ve sürece dahil olan herkes için daha kolay gezilebilir hale getirir. Bu kurallara uymak, herhangi bir mühendislik ekibinin büyük ölçekte yüksek kaliteli yazılımlar geliştirmesine ve sürdürmesine yardımcı olabilir.

