Ders 07 / 10
Platform Tasarım Dilleri Farkı
İki platform aynı işi farklı bir tasarım diliyle sunar. Ders, gezinme kalıbını ekran türünden seçen tek işlevin iki platformda farklı sonuç vermesini dallı olarak sınıflar ve uyarlanmış tasarımın paylaşımı artırdığını ölçer.
Yayın Güncelleme
Bu derste
- Aynı kod platforma göre farklı sonuç veriyorsa özelliği dallı olarak sınıflar
- Gezinme kalıbını, geri davranışını ve sekme yerini platformların tasarım dili farkı olarak tanır
- Aynı davranışı iki ayrı işlevle yazmanın dallı değil ikiz verdiğini ölçer
- Tasarımı iki platformda aynı kalıba uyarlamanın paylaşımı artırdığını, tasarım dilinden sapmayı ise ölçmediğini açıklar
İçindekiler
Önceki konu yaklaşımları karşılaştırdı ve son derste seçim ölçütlerini sıraladı. Ölçütlerden biri, arayüzün iki platformda aynı mı görüneceği yoksa her platformun kendi diliyle mi görüneceğiydi. Bu konu o sorunun arkasındaki gerçekleri açar ve ilk gerçek tasarım dilidir. Kursun sorusu değişmez: bu özelliğin kodu platformlar arasında nasıl paylaşılıyor? Yanıtın dört biçimi ve çekirdeğin adları açılış dersinde tanıtıldı; burada yeniden tanımlanmaz, atıf yapılır.
Kısaca hatırlayalım. Aynı kod her örnekte aynı sonucu veriyorsa özellik ortaktır. Aynı kod en az bir örnekte platforma göre farklı sonuç veriyorsa dallıdır. Özellik iki ayrı işlev nesnesiyle yazılmışsa, sonuçlar aynı çıksa bile ikizdir. Bir platformda hiç yoksa tektir. Üst ad paylaşımdır; bir özelliğin paylaşımı denince bu dört yanıttan biri anlaşılır.
Kuralı çekirdek verir ve her derste aynı dosyayla gelir. Paylaşımı etiket değil kural belirler; kural elle atanmaz.
// sharing.mjs — bir ozelligin kodunun platformlar arasinda nasil paylasildigini siniflandirir export const PLATFORMS = ["ios", "android"]; export class Sharing { constructor(label, impl, samples) { this.label = label; this.total = samples.length; this.missing = PLATFORMS.filter((p) => typeof impl[p] !== "function"); const present = PLATFORMS.filter((p) => !this.missing.includes(p)); this.code = new Set(present.map((p) => impl[p])).size; if (this.missing.length > 0) { this.differ = null; this.verdict = "tek"; return; } this.differ = samples.filter((s) => { const outs = PLATFORMS.map((p) => JSON.stringify(impl[p](s, p))); return new Set(outs).size > 1; }).length; if (this.code > 1) this.verdict = "ikiz"; else this.verdict = this.differ === 0 ? "ortak" : "dalli"; } line() { const detail = this.differ === null ? `eksik=${this.missing.join(",")}` : `fark=${this.differ}/${this.total}`; console.log(`${this.label}: kod=${this.code} | ${detail} -> ${this.verdict}`); } } export function countSharing(items) { for (const name of ["ortak", "dalli", "ikiz", "tek"]) { console.log(`${name}: ${items.filter((s) => s.verdict === name).length}`); } }
Tasarım Dili Neyi Ayırır
Tasarım dili (design language), bir platformun arayüze koyduğu ortak görünüş ve davranış kurallarıdır. Kullanıcı bir platformda ekranların nasıl açıldığını, nasıl kapandığını ve ana gezintinin nerede durduğunu öğrenmiştir. Başka bir platformda aynı işin farklı yapılması, yanlış değil alışılmamış görünür.
Fark üç yerde belirir. Birincisi gezinme kalıbıdır (navigation pattern): ana bölümler arasında geçiş alt sekmeyle, yan çekmeceyle ya da ekran yığınıyla yapılabilir ve her platformun alışkanlığı farklıdır. İkincisi geri davranışıdır: bir platformda ekranın kenarından kaydırmak geri götürür, öbüründe sistemin geri hareketi ya da düğmesi vardır. Üçüncüsü sekme çubuğu ile araç çubuğunun yeridir: aynı sekmeler bir platformda altta, öbüründe üstte durabilir.
Çapraz platform kod bu farkı ikiye bölerek karşılar. Ya tek bir işlev ekran türüne ve platforma bakıp kalıbı seçer, ya da her platform kendi işlevini yazar. İlki dallıdır, ikincisi ikizdir. İkisi de kullanıcıya platformuna uygun görünüş verebilir; fark kodun nasıl paylaşıldığındadır.
Tek İşlev, İki Kalıp
Model, ekran türünden gezinme kalıbını seçen tek bir işlevdir (navigationStyle). Örnekler ekran türleridir: ana ekran, liste, detay, ayarlar. İşlev iki platformda da aynı nesne olarak verilir, yani kod bir tanedir. Ana ekranda iki platform farklı kalıp seçer, ayarlar ekranında da öyle; liste ile detayda ikisi de yığını seçer.
// main.mjs — ekran turunden gezinme kalibini secen tek islev import { Sharing } from "./sharing.mjs"; const screens = ["ana", "liste", "detay", "ayarlar"]; function navigationStyle(screen, platform) { if (screen === "ana") return platform === "ios" ? "alt-sekme" : "alt-cubuk"; if (screen === "ayarlar") return platform === "ios" ? "yigin" : "cekmece"; return "yigin"; } const nav = new Sharing("gezinme-kalibi", { ios: navigationStyle, android: navigationStyle }, screens); nav.line();
gezinme-kalibi: kod=1 | fark=2/4 -> dalli
Kod bir tane, ama dört ekranın ikisinde sonuç platforma göre değişiyor. Bu tanım gereği dallıdır. İşlev kendi içinde platform parametresine bakıyor; ortak kod ile platform farkı aynı yerde buluşuyor. Bir ekip bu yapıyı genellikle tek bir dosyada tutar ve platform farkını bir if içinde okunur bırakır.
Kural burada neyi görmüştür, neyi görmemiştir? Kodun bir olduğunu ve iki örnekte sonucun ayrıldığını görmüştür. İşlevin ne kadar büyüdüğünü görmez: iki dallı bir işlev ile yirmi dallı bir işlev aynı sınıfa girer. Bunu düzyazı söyler.
PG1. Model, bu paylaşımın kuralını kurar; model çerçevenin kendisi değildir. Modelde gezinme kalıbı bir dizgidir ve ekrana hiçbir şey çizilmez. Gerçek bir uygulamada aynı kararı çerçevenin gezinme düzeni verir ve platform kodu şuna benzer.
// Platform kodu: TabRoot
import SwiftUI
struct TabRoot: View {
var body: some View {
TabView {
HomeScreen().tabItem { Label("Ana", systemImage: "house") }
SettingsScreen().tabItem { Label("Ayarlar", systemImage: "gear") }
}
}
}
// Platform kodu: AppScaffold
@Composable
fun AppScaffold(navController: NavHostController) {
Scaffold(bottomBar = { BottomBar(navController) }) { padding ->
NavHost(navController, startDestination = "home", modifier = Modifier.padding(padding)) {
composable("home") { HomeScreen() }
composable("settings") { SettingsScreen() }
}
}
}
İki parça aynı ana ekranı iki ayrı yerel arayüz diliyle yazar. Parçalar çıktı vermez; ölçülen yalnız modeldeki seçimdir. Bu iki parçayı paylaşan ortak bir üst katman varsa, modeldeki navigationStyle gibi, kalıbı ona soran tek bir işlev olurdu.
Üç Özellik, Üç Cevap
Tek bir özellik tablo olmaz. Aynı ekran kümesinde üç özelliği birlikte soralım: geri davranışı, sekme yeri ve marka rengi. Geri davranışı ana ekranda ve diğerlerinde platforma göre ayrılır. Sekme yeri yalnız sekme taşıyan ekranlarda anlam kazanır. Marka rengi ise platformdan bağımsız bir sabittir.
// main.mjs — uc ozellik, ayni dort ekran import { Sharing, countSharing } from "./sharing.mjs"; const screens = ["ana", "liste", "detay", "ayarlar"]; function backBehavior(screen, platform) { if (screen === "ana") return platform === "ios" ? "yok" : "uygulamadan-cik"; return platform === "ios" ? "kenar-kaydirma" : "sistem-geri"; } function tabPlacement(screen, platform) { if (screen === "ana" || screen === "liste") return platform === "ios" ? "alt" : "ust"; return "yok"; } function brandColor() { return "mavi"; } const rows = [ new Sharing("geri-davranisi", { ios: backBehavior, android: backBehavior }, screens), new Sharing("sekme-yeri", { ios: tabPlacement, android: tabPlacement }, screens), new Sharing("marka-rengi", { ios: brandColor, android: brandColor }, screens), ]; rows.forEach((r) => r.line()); countSharing(rows);
geri-davranisi: kod=1 | fark=4/4 -> dalli sekme-yeri: kod=1 | fark=2/4 -> dalli marka-rengi: kod=1 | fark=0/4 -> ortak ortak: 1 dalli: 2 ikiz: 0 tek: 0
Geri davranışı dört ekranın dördünde ayrılır, sekme yeri ikisinde ayrılır. İkisi de tek işlevdir ve ikisi de dallıdır; dallı olmak için her ekranda ayrılmak gerekmez, tek bir örnekte ayrılmak yeter. Marka rengi hiçbir ekranda ayrılmaz ve ortaktır. Burada küçük bir kural da görünür: platformu hiç okumayan, sabit dönüş veren bir işlev her zaman ortak çıkar. Bunun nedeni işlevin iyi paylaşılmış olması değil, ayıracak bir şey taşımamasıdır.
Aynı Davranış, İki İşlev
Geri davranışını başka biçimde yazalım. Bu kez her platform kendi işlevine sahip: biri kenar kaydırmasını, öbürü sistemin geri hareketini bilir. Sonuçlar bir önceki bloktakiyle birebir aynıdır, ama özellik artık iki ayrı işlev nesnesidir.
İkinci özellik daha dikkat çekicidir: ekran başlığının biçimi. İki platformun işlevleri aynı sonucu verir, yine de ayrı yazılmışlardır. Kural sonucu değil nesne sayısını sayar, bu yüzden bu da ikizdir.
// main.mjs — ayni davranis, iki ayri islev import { Sharing } from "./sharing.mjs"; const screens = ["ana", "liste", "detay", "ayarlar"]; function iosBack(screen) { return screen === "ana" ? "yok" : "kenar-kaydirma"; } function androidBack(screen) { return screen === "ana" ? "uygulamadan-cik" : "sistem-geri"; } const titleIos = (screen) => screen.toUpperCase(); const titleAndroid = (screen) => screen.toUpperCase(); new Sharing("geri-davranisi-ikiz", { ios: iosBack, android: androidBack }, screens).line(); new Sharing("baslik-bicimi", { ios: titleIos, android: titleAndroid }, screens).line();
geri-davranisi-ikiz: kod=2 | fark=4/4 -> ikiz baslik-bicimi: kod=2 | fark=0/4 -> ikiz
Geri davranışı bu kez ikiz çıktı, ama sonuçlar önceki bloktakiyle aynı: dört ekranın dördünde ayrılıyor. Değişen yalnız kodun biçimidir. Başlık biçimi daha da açık bir örnek: iki işlev aynı sonucu veriyor, fark sıfır, yine de kod iki. Kural burada iki şeyi birlikte söyler: sonuç ortak, kod ikiz.
Bu ayrımın bedeli gerçektir. Dallı bir özellikte platform farkı tek yerde okunur; ikiz bir özellikte aynı farkı sürdürmek için iki işlevi birlikte güncellemek gerekir. Kural bu bedeli görmez: üç satırlık bir ikiz ile üç yüz satırlık bir ikiz aynı sınıfa girer. Büyüklüğü düzyazı söyler.
Sınırlayıcı Ölçüm
Tasarımı platformlara bırakmak yerine iki platformda aynı kalıba uyarlayalım. Ana ekranda alt sekme, diğer her yerde yığın: iki platform da aynı kararı verir. İşlev tek, sonuç her ekranda aynı.
// main.mjs — iki platformda ayni kalibi veren uyarlanmis tasarim import { Sharing, countSharing } from "./sharing.mjs"; const screens = ["ana", "liste", "detay", "ayarlar"]; function navigationStyle(screen, platform) { if (screen === "ana") return platform === "ios" ? "alt-sekme" : "alt-cubuk"; if (screen === "ayarlar") return platform === "ios" ? "yigin" : "cekmece"; return "yigin"; } function adaptedNavigation(screen) { return screen === "ana" ? "alt-sekme" : "yigin"; } const rows = [ new Sharing("gezinme-kalibi-platforma-gore", { ios: navigationStyle, android: navigationStyle }, screens), new Sharing("gezinme-kalibi-uyarlanmis", { ios: adaptedNavigation, android: adaptedNavigation }, screens), ]; rows.forEach((r) => r.line()); countSharing(rows);
gezinme-kalibi-platforma-gore: kod=1 | fark=2/4 -> dalli gezinme-kalibi-uyarlanmis: kod=1 | fark=0/4 -> ortak ortak: 1 dalli: 1 ikiz: 0 tek: 0
Aynı özellik ilk satırda dallıydı, ikinci satırda ortak oldu. Kod değişmedi, hâlâ tek işlev; değişen, işlevin platforma göre ayrılmayı bırakmasıdır. Paylaşım arttı: dallıdan ortağa geçildi.
Kuralın göremediği şey bu geçişin bedelidir. Ortak kalıp, platformlardan birinin tasarım dilinden sapar: ana ekranda alt sekme bir platformda alışkanlıkla örtüşürken öbüründe örtüşmeyebilir. Bu sapmayı model ölçmez ve ölçemez, çünkü kullanıcı alışkanlığı bir işlev çağrısının sonucu değildir. Ölçülen yalnız şudur: ortak kalıp iki platformda da aynı sonucu verir. Alışkanlıktan ne kadar uzaklaşıldığı düzyazıda söylenen ve ekibin kendisinin tarttığı bir karardır.
PG2. Model, bir kalıbın iki platformda aynı sonucu verdiğini ölçer, kullanıcının o kalıbı doğal bulup bulmadığını ölçmez. Bu varsayım tasarım kararı yerine geçmez. Ortak paylaşımın tasarım dilinden bir sapma içerdiğini bilmek, sapmanın kabul edilebilir olduğunu söylemez.
Özet
- Bu dersin paylaşımı: dallı. Gezinme kalıbını ekran türünden seçen tek işlev, dört ekranın ikisinde platforma göre farklı kalıp verdi.
- Dört ölçümde dallı, ikiz ve ortak çıktı: geri davranışı ve sekme yeri dallı, aynı geri davranışı iki işlevle yazılınca ikiz, marka rengi ortaktı.
- Platformu okumayan, sabit dönüş veren bir işlev her zaman ortak çıkar; bu işlevin iyi paylaşıldığını değil, ayıracak bir şey taşımadığını gösterir.
- Başlık biçimi iki işlevle aynı sonucu verse de ikiz çıktı: kural sonucu değil kodun biçimini sayar.
- Tasarımı iki platformda aynı kalıba uyarlamak paylaşımı dallıdan ortağa çıkarır; tasarım dilinden sapmayı kural değil düzyazı söyler.
Sonraki Adım
Gezinme kalıbı ortak koddan seçilebildi, çünkü seçim yalnız bir dizgiydi. Platformun kendi yeteneğine dokunan bir iş böyle çözülmez: biyometrik doğrulama isteğini ortak kod tek başına yapamaz. Sıradaki ders, Yerel Modül İhtiyacı, böyle bir isteği yapan kodun platformlar arasında nasıl paylaşıldığını ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.