Ders 03 / 14
Yapılandırma ve Ortam Yönetimi
Yapılandırma ve ortam yönetimi, aynı uygulamanın geliştirme, hazırlık ve üretim ortamlarında farklı değerlerle çalışmasını sağlar. Ders varsayılandan açılan bir bayrağın özelliği tam bıraktığını ölçer.
Yayın Güncelleme
Bu derste
- Geliştirme, hazırlık ve üretim ortamlarını ayırmanın gerekçesini açıklar
- Gizli değerin yapıya gömülmeden nasıl taşındığını anlatır
- Uzaktan yapılandırma, özellik bayrağı ve varsayılan değer arasındaki ilişkiyi kurar
- Varsayılandan gelen bir bayrağın özelliği tam bıraktığını ölçer
İçindekiler
Önceki derste görünüm platforma göre uyarlandı. Bu derste değişen şey platform değil, uygulamanın çalıştığı ortamdır. Aynı derleme geliştiricinin makinesinde, sınama ekibinin elinde ve gerçek kullanıcıda koşar; üçünde de aynı sunucuya konuşmaz, aynı günlük ayrıntısını yazmaz, aynı bayrakları açık bulmaz. Yapılandırma, bu farkı koda dokunmadan taşıyan düzenektir. Ders önce yapılandırmanın parçalarını anlatır, sonra uzaktan yapılandırmaya ulaşılamayan bir ilk açılışta bir özelliğin ne kadar çalıştığını ölçer.
Ortamlar ve Yapılandırma Katmanları
Ortam, uygulamanın hangi amaçla ve hangi arka uca karşı çalıştığını adlandırır. Üç ortam yaygındır: geliştirme ortamı tek geliştiricinindir ve her şeyin hızlıca denenmesine izin verir; hazırlık ortamı üretime benzer ama gerçek veri taşımaz; üretim ortamı gerçek kullanıcıların kullandığı ortamdır. Ortamları ayırmanın kazancı hatayı doğru yerde yakalamaktır: bir değişiklik önce geliştirmede, sonra hazırlıkta sınanır ve ancak sonra üretime çıkar.
Her ortamın kendi yapılandırması vardır: sunucu adresi, günlük ayrıntısı, bir hizmetin anahtarı. Bu değerlerin kod içine yazılması iki sorun doğurur. Birincisi, ortam değişince kodun değişmesi gerekir ve kod değişince sınanmış yapı artık sınanmış yapı olmaz. İkincisi, anahtar gibi değerler kodla birlikte depoya girer. Bu yüzden değerler koddan ayrılır ve derleme sırasında ortama göre seçilir.
Aşağıdaki parça bu ayrımı bir yapılandırma dosyasında gösterir. Gizli değerin kendisi dosyada durmaz; yalnız adı durur ve gerçek değer derleme düzeneğinin gizli deposundan yerine konur. Parça ölçülmez.
# Platform kodu: ortam basina yapilandirma environments: staging: api_host: api.staging.example.test api_key: ${API_KEY} # gizli depodan derleme aninda yerine konur log_level: ayrintili production: api_host: api.example.test api_key: ${API_KEY} log_level: sade defaults: search: true # uzaktan yapilandirma gelmezse gecerli deger banner: false
Gizli değer, açığa çıkması hâlinde bir hizmetin kötüye kullanılmasına yol açan değerdir: bir anahtar, bir parola, bir imza anahtarı. Kural basittir ve istisnasız uygulanır: gizli değer koda, yapılandırma dosyasına ve uygulama paketine gömülmez. Pakete giren her şey paketi açan herkesin okuyabileceği şeydir. Gizli değer derleme düzeneğinin gizli deposunda durur, yapılandırma yalnız onun adını taşır. Gerçekten istemcide kalmaması gereken bir değer ise hiç istemciye gönderilmez; sunucuda durur.
Varsayılan Değer ve Uzaktan Yapılandırma
Bazı değerler derleme anında sabitlenemez, çünkü kullanıcı uygulamayı yükledikten sonra da değişmeleri gerekir. Uzaktan yapılandırma, uygulamanın çalışırken bir sunucudan değer almasıdır. En yaygın kullanımı özellik bayrağıdır: bir özelliğin açık ya da kapalı olduğunu kod değişmeden belirleyen bir değer. Bayrağın özel bir türü uzaktan kapatma bayrağıdır: üretimde sorun çıkaran bir özelliği yeni sürüm beklemeden kapatan bayrak.
Uzaktan yapılandırmanın bir kusuru vardır: sunucuya ulaşılamayabilir. İlk açılışta ağ olmayabilir, sunucu geçici olarak yanıt vermeyebilir, kullanıcı uçak kipinde olabilir. Bu durumda uygulamanın bir değeri olmalıdır. İşte varsayılan değer budur: paketin içinde gelen, uzaktan hiçbir şey alınamadığında geçerli olan değer. Uygulama değeri şu sırayla çözer: uzaktan gelen değer varsa o, yoksa varsayılan.
Varsayılanın seçimi bir ürün kararıdır ve iki yönde riski vardır. Varsayılan açık olursa özellik, uzaktan yapılandırma gelmese de çalışır; ama kapatılması gereken bir özellik ilk açılışta açık kalır. Varsayılan kapalı olursa özellik güvenle kapalıdır; ama ilk açılışta kullanıcı özelliği hiç görmez. Ders bu seçimin işlerliğe nasıl yansıdığını ölçer.
Koşuldan Yeteneğe
Model yapılandırmayı bir koşula çevirir. configFor(name, remote, defaults) ortamın bayraklarını çözer: uzaktan değer varsa onu, yoksa varsayılanı alır. Açık her bayrak koşulun has listesine flag:<ad> biçiminde bir yetenek olarak girer. Bir özellik bir bayrağa ihtiyaç duyuyorsa needs listesinde o yeteneği ister. Dersin çekirdeği her derste olduğu gibi aşağıda yeniden verilir.
// operability.mjs — bir ozelligin bir kosulda ne kadar calistigini siniflandirir export const LEVELS = ["tam", "kisitli", "ertelenen", "kapali"]; const FALLBACKS = ["kisitli", "ertelenen"]; export function feature(name, needs, fallback = {}) { return { name, needs, fallback }; } export function condition(name, has) { return { name, has }; } function judge(item, cond) { const missing = item.needs.filter((need) => !cond.has.includes(need)).sort(); let level = "tam"; for (const need of missing) { const given = FALLBACKS.includes(item.fallback[need]) ? item.fallback[need] : "kapali"; if (LEVELS.indexOf(given) > LEVELS.indexOf(level)) level = given; } return { level, feature: item.name, condition: cond.name, missing }; } export function assess(features, conditions) { const records = []; for (const cond of conditions) { for (const item of features) records.push(judge(item, cond)); } return records; } export function printLevels(records) { for (const r of records) { const missing = r.missing.length === 0 ? "-" : r.missing.join(","); console.log(`${r.level}: ${r.feature} @ ${r.condition} eksik=${missing}`); } } export function countLevels(records) { for (const name of LEVELS) { console.log(`${name}: ${records.filter((r) => r.level === name).length}`); } console.log(`etkilenen: ${records.filter((r) => r.level !== "tam").length}`); }
Yapılandırma yardımcısı ders-yerel bir dosyadır. Ortam tablosu gizli değeri değil, onun adını tutar.
// config.mjs — ortam tablosu, varsayilan degerler ve bayrak cozumu import { condition } from "./operability.mjs"; export const ENVS = { dev: { host: "dev.example.test", logs: "ayrintili", secret: "ref:API_KEY_DEV" }, staging: { host: "staging.example.test", logs: "ayrintili", secret: "ref:API_KEY_STG" }, prod: { host: "api.example.test", logs: "sade", secret: "ref:API_KEY_PROD" }, }; export const DEFAULTS = { search: true, banner: false }; export function configFor(name, remote = null, defaults = DEFAULTS) { const flags = { ...defaults, ...(remote ?? {}) }; const has = Object.keys(flags) .filter((key) => flags[key]) .sort() .map((key) => `flag:${key}`); return condition(name, has); }
İlk ölçüm işlerlik değildir; üç ortamın tablosunu basar.
// main.mjs import { ENVS } from "./config.mjs"; for (const name of Object.keys(ENVS)) { const env = ENVS[name]; console.log(`${name}: host=${env.host} logs=${env.logs} secret=${env.secret}`); }
dev: host=dev.example.test logs=ayrintili secret=ref:API_KEY_DEV staging: host=staging.example.test logs=ayrintili secret=ref:API_KEY_STG prod: host=api.example.test logs=sade secret=ref:API_KEY_PROD
secret alanı bir değer değil gizli depodaki bir kaydın adıdır. Üç ortam üç ayrı gizli değere işaret eder ve hiçbirinin değeri tabloda görünmez.
PM5. Alan adları, sunucu adresleri ve gizli değer adları dersin kurgusudur ve example.test alanı gerçek bir sunucuya çıkmaz. Model, gizli değerin çözülmesini, uzaktan yapılandırmanın ağdan alınmasını ve bir bayrağın sunucuda nasıl tanımlandığını içermez; yalnız bayrağın açık ya da kapalı olduğunu ve bunun bir yetenek olarak koşula girdiğini kurar.
Uzaktan Kapatma Bayrağı
İkinci ölçüm iki özelliği üretim ortamında iki durumda sınar. Search yeni arama özelliğidir ve flag:search ister. Banner ise flag:banner ister ve bayrak yoksa sade bir düzene düşer. İlk koşulda uzaktan yapılandırmaya hiç ulaşılamamıştır, yalnız varsayılanlar geçerlidir. İkinci koşulda uzaktan yapılandırma gelmiş ve arama bayrağını kapatmıştır.
// main.mjs import { feature, assess, printLevels } from "./operability.mjs"; import { configFor } from "./config.mjs"; const features = [ feature("Search", ["flag:search"]), feature("Banner", ["flag:banner"], { "flag:banner": "kisitli" }), ]; const conditions = [ configFor("prod-default"), configFor("prod-remote", { search: false }), ]; printLevels(assess(features, conditions));
tam: Search @ prod-default eksik=- kisitli: Banner @ prod-default eksik=flag:banner kapali: Search @ prod-remote eksik=flag:search kisitli: Banner @ prod-remote eksik=flag:banner
Üç şey görünür. Varsayılan koşulda Search tamdır, çünkü varsayılanda arama açıktır. Banner varsayılanda kapalıdır; ama bir yedeği vardır, sade düzen, bu yüzden kapalı değil kısıtlıdır. Uzaktan kapatma bayrağı geldiğinde Search kapalıya düşer, çünkü arama için tanımlı bir yedek yoktur. Uzaktan kapatma bayrağının amacı da budur: özelliği yeni sürüm beklemeden devreden çıkarmak.
PM6. Bayrak adları ve varsayılan değerleri dersin kurgusudur. Gerçek bir uygulamada arama özelliğinin kapalıyken ne göstereceği ayrı bir ürün kararıdır; model yalnız yedeğin var olup olmadığını bilir.
Sınırlayıcı Ölçüm
Dersin odak kaydı Search @ prod-default’tur: ilk açılışta, uzaktan yapılandırmaya ulaşılamazken, yeni arama bayrağı varsayılandan gelir. Varsayılan açıktır, bu yüzden yetenek vardır ve kayıt tamdır. Karşılaştırma için aynı koşulun varsayılanı kapalı olan bir benzeri eklenir.
// main.mjs import { feature, assess, printLevels } from "./operability.mjs"; import { configFor, DEFAULTS } from "./config.mjs"; const features = [feature("Search", ["flag:search"])]; const conditions = [ configFor("prod-default"), configFor("prod-default-off", null, { ...DEFAULTS, search: false }), ]; printLevels(assess(features, conditions));
tam: Search @ prod-default eksik=- kapali: Search @ prod-default-off eksik=flag:search
Varsayılan açıkken kayıt tam, kapalıyken kapalıdır. Fark değerin kendisidir: açık bir bayrak yetenek olarak koşula girer, kapalı bir bayrak girmez.
Bu sonuç M31/K04’ün sorusundan farklıdır. O ders bir okumanın kökenini sordu: yanıt bellekten mi, diskten mi, ağdan mı, varsayılandan mı geldi. Uzaktan yapılandırmanın değeri varsayılandan gelse de özellik tam olabilir; işlerlik değerin kaynağını değil, yeteneğin varlığını sınıflar. Aşağıdaki ölçüm bunu doğrudan gösterir. Aynı bayrak bir koşulda varsayılandan, ötekinde uzaktan gelir ve iki kayıt karşılaştırılır.
// main.mjs import { feature, assess } from "./operability.mjs"; import { configFor } from "./config.mjs"; const features = [feature("Search", ["flag:search"])]; const fromDefault = assess(features, [configFor("prod")]); const fromRemote = assess(features, [configFor("prod", { search: true })]); console.log(JSON.stringify(fromDefault) === JSON.stringify(fromRemote) ? "kayit ayni" : "kayit degisti");
kayit ayni
Değer bir koşulda varsayılandan, ötekinde uzaktan geldi; kayıt aynı kaldı. Kaynak kayda girmez. Bu, kaynağın önemsiz olduğu anlamına gelmez: bir ekip varsayılanı güvenli seçmek ve uzaktan değerin gecikmesini bilmek zorundadır. Ama bunlar okumanın kökenine dair sorulardır; işlerlik soruyu başka yerden sorar: bu koşulda bu özellik ne kadar çalışıyor?
Özet
- Bu dersin işlerliği: tam.
Search @ prod-defaultkaydında uzaktan yapılandırmaya ulaşılamasa da arama bayrağı varsayılandan açıktır ve yetenek vardır. - Aynı bayrağın varsayılanı kapalı olsaydı
Search @ prod-default-offkapalı çıkardı; fark değerin kaynağında değil, yeteneğin varlığındadır. - Varsayılandan ve uzaktan gelen aynı açık değer aynı kaydı verdi; işlerlik değerin kaynağını kayda katmaz.
- Uzaktan kapatma bayrağı gelince yedeği olmayan
Searchkapalıya, yedeği olanBannerkısıtlıya düştü. - Gizli değer koda, yapılandırma dosyasına ve pakete gömülmez; yapılandırma yalnız adını taşır.
Sonraki Adım
Bu derste yetenek bir yapılandırma değerinden geldi ve özellik tam kaldı. Sıradaki ders, Erişilebilirlik, yeteneğin kullanıcının kendi ayarından düştüğü durumu ele alır: ekran okuyucu açıldığında görünüm ağacında hiçbir düğüm değişmeden bir özellik kısıtlıya düşebilir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.