Ders 01 / 14
Modüler Kod Paylaşımı
Modüler kod paylaşımı, ortak kodu paylaşılan modüle ve platforma özgü katmana ayırır. Ders kursun işlerlik ölçüsünü kurar ve tamamen paylaşılan bir modülün bir platformda kapalı kalabildiğini ölçer.
Yayın Güncelleme
Bu derste
- Paylaşılan modül ile platforma özgü katman arasındaki katman sınırını açıklar
- Bir özelliğin işlerliğini tam, kısıtlı, ertelenen ve kapalı olarak sınıflar
- Dokuz kayıtlık açılış ölçümünü okur ve etkilenen kayıtları ayırır
- Tamamen paylaşılan bir modülün bir platformda neden kapalı kaldığını ölçer
İçindekiler
Önceki kurslar bir çapraz platform uygulamasının nasıl kurulduğunu sordu: kod platformlar arasında nasıl paylaşılıyor, görünüm ağacı nasıl güncelleniyor, bir bileşenin genişliğini kim belirliyor. Üretimdeki bir uygulama için asıl soru başkadır. Aynı ekran bir aygıtta çevrimiçi, ötekinde çevrimdışı açılır; bir üçüncüsünde arka plan işi kısılmıştır; bir dördüncüsü eski bir istemci sürümünü çalıştırır. Tek bir uygulama tek bir koşulda çalışmaz.
Bu kurs her özelliği tek bir soruyla sınıflar: bu koşulda bu özellik ne kadar çalışıyor? İlk ders soruyu kurar ve ilk konunun konusuna, ortak kodun nasıl dilimlendiğine bağlar. Bu kursta “özellik” bir uygulama özelliği, yani feature demektir: kullanıcının yaptığı bir iş, örneğin katalog gezmek ya da ödeme yapmak. Bir bileşenin dışarıdan aldığı değer anlamına gelmez.
Dört İşlerlik
Sorunun yanıtına işlerlik denir ve dört değeri vardır. Kurs boyunca bu dört ad değişmez.
- tam: özelliğin ihtiyaç duyduğu her yetenek bu koşulda vardır; özellik tasarlandığı gibi çalışır.
- kısıtlı: bir yetenek eksiktir; özellik eksik yeteneğin yerine daha az şey yaparak hemen çalışır, örneğin önbellekteki içeriği gösterir.
- ertelenen: bir yetenek eksiktir; özelliğin işi kaybolmaz, sonraya bırakılır ve yetenek dönünce yapılır.
- kapalı: eksik yeteneklerden en az birinin yedeği yoktur; özellik bu koşulda çalışmaz.
Çıktıda bu adlar ASCII yazılır: tam, kisitli, ertelenen, kapali. Kapalı ile ertelenen aynı şey değildir. Kapalı bir özelliğin işi o koşulda yapılmaz ve sonraya da kalmaz; ertelenen bir özelliğin işi ise yerinde durur.
İşlerliği bir etiket değil, bir kural verir. Özellik ihtiyaç duyduğu yetenekleri sayar, koşul o anda var olan yetenekleri sayar, aradaki fark eksikleri verir. Her eksik için özellik bir yedek tanımlamış olabilir. Kural sırayla üç soru sorar:
- Eksik yetenek yoksa özellik tamdır.
- Eksik yeteneklerden birinin yedeği yoksa özellik kapalıdır.
- Aksi hâlde eksik yeteneklerin yedeklerinden en ağırı seçilir; ertelenen, kısıtlıdan ağırdır.
Bu üç soru çekirdeğin içinde kod olarak durur. Çekirdek bu kursun her dersinde aynı biçimde yeniden verilir; ilk kez burada okunur.
// 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}`); }
feature(name, needs, fallback) bir özellik kurar: needs ihtiyaç duyduğu yetenekleri, fallback bir yetenek eksik olduğunda neye düşeceğini söyler. fallback verilmezse boştur; o özelliğin hiçbir yeteneğinin yedeği yoktur ve her eksik onu kapalıya düşürür. condition(name, has) bir koşul kurar; has o koşulda var olan yeteneklerdir. Yetenek bir dizgidir (network, background, storage) ve çekirdek onu yorumlamaz, yalnız has içinde olup olmadığına bakar.
assess her koşul için her özelliği değerlendirir: koşul dışta, özellik içte döner. Her kayıt level, feature, condition ve missing alanlarını taşır. printLevels kayıtları basar; countLevels dört işlerliği sabit sırayla sayar ve son satırda etkilenen toplamını verir. Etkilenen, kısıtlı, ertelenen ve kapalı kayıtların toplamıdır: özelliğin tasarlandığı gibi çalışmadığı kayıt sayısı. Tam kayıt bu sayıya girmez.
Dokuz Kayıt
Senaryo, paylaşılan kodla iki platformda yayımlanan bir mağaza uygulamasıdır. Üç özellik vardır. Catalog ağdan içerik okur; ağ yokken önbellekteki içeriğe düşer. Checkout ödeme yapar ve hiçbir yedeği yoktur. PhotoUpload fotoğraf gönderir; hem ağa hem arka plan işine ihtiyaç duyar ve ikisinin yokluğunda da işini sonraya bırakır. Üç koşul vardır: online her yeteneği taşır, offline ağı kaybeder, low-power ağı korur ama arka plan işini kaybeder.
// main.mjs import { feature, condition, assess, printLevels, countLevels } from "./operability.mjs"; const features = [ feature("Catalog", ["network"], { network: "kisitli" }), feature("Checkout", ["network"]), feature("PhotoUpload", ["network", "background"], { network: "ertelenen", background: "ertelenen", }), ]; const conditions = [ condition("online", ["network", "background"]), condition("offline", ["background"]), condition("low-power", ["network"]), ]; const records = assess(features, conditions); printLevels(records); countLevels(records);
tam: Catalog @ online eksik=- tam: Checkout @ online eksik=- tam: PhotoUpload @ online eksik=- kisitli: Catalog @ offline eksik=network kapali: Checkout @ offline eksik=network ertelenen: PhotoUpload @ offline eksik=network tam: Catalog @ low-power eksik=- tam: Checkout @ low-power eksik=- ertelenen: PhotoUpload @ low-power eksik=background tam: 5 kisitli: 1 ertelenen: 2 kapali: 1 etkilenen: 4
İlk üç satır online koşuludur: her yetenek vardır, üç özellik de tamdır. offline koşulunda ağ yoktur. Catalog ağ için yedek tanımladığı için kısıtlıdır, PhotoUpload işini sonraya bıraktığı için ertelenendir, Checkout’un yedeği olmadığı için Checkout @ offline kapalıdır. low-power koşulunda ağ vardır ama arka plan yoktur: arka plana ihtiyaç duymayan Catalog ve Checkout tamdır, PhotoUpload ertelenendir.
Dokuz kaydın beşi tam, biri kısıtlı, ikisi ertelenen, biri kapalıdır; etkilenen dört. Bu sayı kursun açılış sayısıdır. Sonraki dersler ona atıfla anar, değiştirmez; her ders kendi kesitini ayrıca ölçer. Kullanıcıya hiçbir şey sunmayan tek kayıt Checkout @ offline’dır. Etkilenen dört kaydın üçünde özellik bir şekilde çalışmayı sürdürür.
PM1. Model, bir özelliğin bir koşuldaki davranışını yalnız yetenek kümesi olarak taklit eder. Kural yeteneği ve yedeği görür; işin kendisini, kullanıcıyı ve süreyi görmez. Kısıtlı Catalog’un önbellekteki içeriği ne kadar eski göstereceği, ertelenen PhotoUpload’ın işi ne zaman yapacağı ve kaç kez deneyeceği modelde yoktur ve işlerliği değiştirmez. Model, bu işlerliğin kuralını kurar; model çerçevenin kendisi değildir.
Paylaşılan Modül ve Platforma Özgü Katman
Çapraz platform bir uygulamada kod iki parçaya ayrılır. Paylaşılan modül iki platformda aynı yazılan koddur: iş kuralları, veri modeli, akış mantığı. Platforma özgü katman her platformun kendi dilinde ve kendi API’siyle yazılan koddur: kamera, bildirim, dosya sistemi, biyometri. Paylaşılan modül bu yeteneklere doğrudan uzanmaz. İstediğini bir sözleşme olarak söyler; platforma özgü katman sözleşmeyi karşılar.
İki parçanın arasındaki çizgiye katman sınırı denir. Sınırın iyi çizilmesi, platforma özgü kodun az ve dar kalması demektir: paylaşılan modül ne istediğini söyler, hangi platformda nasıl karşılandığını bilmez. Aşağıdaki parça sözleşmeyi ve onu kullanan paylaşılan özelliği gösterir. Parça ölçülmez.
// Platform kodu: paylasilan sozlesme
interface PlatformLayer {
val hasScanner: Boolean
fun scan(onCode: (String) -> Unit)
}
class ScanFeature(private val layer: PlatformLayer) {
fun open(onCode: (String) -> Unit): Boolean {
if (!layer.hasScanner) return false
layer.scan(onCode)
return true
}
}
ScanFeature iki platformda aynı koddur. Yeteneğin varlığını katmana sorar; yoksa false döner ve hiçbir şey olmaz. Sözleşmenin iki karşılığı platforma göre ayrılır. Android tarafı Kotlin’dedir, iOS tarafı aynı sözleşmenin Swift karşılığına uyar.
// Platform kodu: Android katmani (tarayici henuz yazilmadi)
class AndroidLayer : PlatformLayer {
override val hasScanner = false
override fun scan(onCode: (String) -> Unit) = Unit
}
// Platform kodu: iOS katmani
final class IosLayer: PlatformLayer {
let hasScanner = true
func scan(onCode: @escaping (String) -> Void) {
// kamera oturumu kurulur, okunan kod onCode ile iletilir
}
}
Model bu ayrımı bir işlevle kurar. platformLayer(platform) bir platformun katmanından koşul üretir: katman bir yeteneği karşılıyorsa koşulun has listesinde o yetenek vardır, karşılamıyorsa yoktur. Gerçek uygulamada yetenek kümesini kod aygıtın ve katmanın durumundan üretir; model de aynı yolu izler.
// layers.mjs — platforma ozgu katmanin sundugu yetenekleri uretir import { condition } from "./operability.mjs"; const LAYERS = { ios: ["network", "storage", "scanner"], android: ["network", "storage"], }; export function platformLayer(platform, written = []) { return condition(platform, [...LAYERS[platform], ...written]); }
İlk ölçümde iki özellik iki katmana karşı değerlendirilir. İkisi de yalnız her iki katmanın karşıladığı yeteneklere ihtiyaç duyar.
// main.mjs import { feature, assess, printLevels } from "./operability.mjs"; import { platformLayer } from "./layers.mjs"; const features = [ feature("Catalog", ["network"], { network: "kisitli" }), feature("Profile", ["storage"]), ]; const conditions = [platformLayer("ios"), platformLayer("android")]; printLevels(assess(features, conditions));
tam: Catalog @ ios eksik=- tam: Profile @ ios eksik=- tam: Catalog @ android eksik=- tam: Profile @ android eksik=-
Dört kaydın dördü tamdır. Paylaşılan kodun iki platformda aynı işi gördüğü durum budur ve sık görülen durum da budur. Sınır, katmanın bir yeteneği karşılamadığı yerde görünür olur.
Sınırlayıcı Ölçüm
Sınırlayıcı ölçümde listeye tek bir özellik eklenir: Scan. Tarama özelliğinin iş mantığı paylaşılan modüldedir ve iki platformda aynı koddur. Ama kamerayı kullanabilmek için scanner yeteneği gerekir ve bu yetenek platforma özgü katmandan gelir. Senaryoda katman iOS için yazılmıştır, Android için henüz yazılmamıştır. Scan için yedek tanımlanmamıştır.
// main.mjs import { feature, assess, printLevels, countLevels } from "./operability.mjs"; import { platformLayer } from "./layers.mjs"; const features = [ feature("Catalog", ["network"], { network: "kisitli" }), feature("Scan", ["scanner"]), ]; const conditions = [platformLayer("ios"), platformLayer("android")]; const records = assess(features, conditions); printLevels(records); countLevels(records);
tam: Catalog @ ios eksik=- tam: Scan @ ios eksik=- tam: Catalog @ android eksik=- kapali: Scan @ android eksik=scanner tam: 3 kisitli: 0 ertelenen: 0 kapali: 1 etkilenen: 1
Dersin odak kaydı Scan @ android‘dir ve kapalı çıkar. Scan iki platformda aynı paylaşılan koddur; iOS’ta tamdır. Android’de scanner yeteneği eksiktir, özelliğin o yetenek için yedeği yoktur, bu yüzden kural ikinci soruda kapalıya varır. Bu ölçümün etkilenen sayısı bir, açılıştaki dört değildir; iki ölçüm farklı kümeleri sayar.
PM2. Model, Android’de kameranın kullanılamadığını söylemez. Senaryo yalnız bu uygulamanın Android katmanında tarayıcı sözleşmesinin henüz karşılanmadığını kurar. scanner dersin kurgusudur ve çekirdek onu yorumlamaz. Katmanı yazmanın ne kadar iş olduğu modelde yoktur.
Bu sonuç M32/K01’in sorusundan farklıdır. O ders kodun platformlar arasındaki dağılımını sordu: ne kadarı paylaşılıyor, ne kadarı platforma özgü. İşlerlik bu soruyu sormaz. Tamamen paylaşılan bir modül de bir platformun koşulunda kapalı olabilir; işlerlik kodun nerede yazıldığını değil, o koşulda ne kadar çalıştığını sınıflar. Kodun ne kadarının paylaşıldığı kaydı değiştirmez, çünkü feature bir paylaşım oranı taşımaz ve kural yalnız needs, fallback ve has’e bakar. Scan’in iş mantığının tamamı paylaşılsa da bir kısmı paylaşılsa da Scan @ android aynı kalır.
Kapalıyı değiştiren şey platformun katmanıdır. İkinci ölçüm Android katmanına scanner yeteneğini yazdırır ve aynı özelliği yeniden değerlendirir.
// main.mjs import { feature, assess, printLevels } from "./operability.mjs"; import { platformLayer } from "./layers.mjs"; const scan = [feature("Scan", ["scanner"])]; printLevels(assess(scan, [platformLayer("android")])); printLevels(assess(scan, [platformLayer("android", ["scanner"])]));
kapali: Scan @ android eksik=scanner tam: Scan @ android eksik=-
Paylaşılan modüldeki tek satır değişmedi; yalnız katman yeteneği karşıladı ve kayıt tama döndü. Kapalının bir başka çıkışı da yedek tasarlamaktır. Scan için kodun elle girilmesi gibi bir yedek tanımlansaydı aynı kayıt kısıtlı olurdu. Kapalı olması, bir yedeğin tasarlanmadığını söyler.
Özet
- Bu dersin işlerliği: kapalı.
Scan @ androidkaydındascanneryeteneği eksiktir ve yedeği yoktur; paylaşılan modül tamamen ortak olsa da kayıt kapalı çıkar. - İşlerlik bir kuralın çıktısıdır: eksik yetenek yoksa tam, yedeği olmayan bir eksik varsa kapalı, aksi hâlde eksiklerin en ağır yedeği (ertelenen, kısıtlıdan ağırdır).
- Açılış ölçümünde dokuz kaydın beşi tam, biri kısıtlı, ikisi ertelenen, biri kapalı çıktı; etkilenen dört.
- Paylaşılan modül sözleşmeyi söyler, platforma özgü katman yeteneği karşılar; katman sınırı bu çizgidir.
- Kodun paylaşım oranı kaydı değiştirmez;
Scan @ androidkapalıdan tama ancak Android katmanıscanneryeteneğini karşılayınca döndü.
Sonraki Adım
Bu derste platforma göre değişen şey bir yetenekti ve eksik olduğunda özellik kapandı. Sıradaki ders, Tasarım Sistemi Uyarlaması, platforma göre değişen şeyin görünüm olduğu durumu ölçer: tek bir tasarım dili iki platformda farklı biçimde uyarlanır ve bir tarih seçici iki biçimde de tam çalışır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.