İçeriğe geç
academia.sh

Ders 15 / 15

Çerçeve Seçimi

Aynı modelden bildirimsel ve buyurgan iki ekran kurup aynı kuralla denetlemenin ölçümü ve uyumun bir çerçeve seçim ölçütü olmadığının gösterimi; kursun on beş dersinin kapanış tablosu.

Yayın Güncelleme

Bu derste

  • Aynı modelin bildirimsel ve buyurgan iki ekranını aynı kuralla denetler
  • Buyurgan tarafta unutulan alanın eksik, güncellenmeyen alanın bayat ölçüldüğünü gösterir
  • Uyumun bir çerçeve seçim ölçütü olmadığını iki yönde bozulan ekranla doğrular
  • Seçim gerekçelerini ekip, eski kod, platform sürümü ve özel çizim üzerinden sayıya dökmeden anlatır
İçindekiler

Önceki derste eski bir ekranı ekran ekran yeni çerçeveye taşıdık ve kuralın alan başına çalıştığını gördük. Bu konunun son sorusu kaçınılmaz olarak şudur: yeni bir ekran yazılacaksa hangi çerçeve seçilmeli? Kursun ölçüsü bu soruya cevap vermez, ve bu dersin işi tam olarak bunu göstermektir. Ölçü ekseni değişmedi: uyum. Çekirdek dosya önceki derslerle aynıdır.

// Sync.swift — ekranda gosterilen her alani modelin o anki degeriyle karsilastirir
final class Screen {
    let name: String
    private(set) var shown: [String: String] = [:]

    init(_ name: String) { self.name = name }

    func set(_ key: String, _ value: String) { shown[key] = value }
    func clear(_ key: String) { shown[key] = nil }
}

func verdict(model: String?, shown: String?) -> String {
    switch (model, shown) {
    case (nil, nil): return "olcum-disi"
    case (nil, _?): return "artik"
    case (_?, nil): return "eksik"
    case let (wanted?, displayed?): return wanted == displayed ? "uyumlu" : "bayat"
    }
}

func check(_ label: String, model: [String: String], screen: Screen, keys: [String]) -> [String] {
    keys.map { key in
        let result = verdict(model: model[key], shown: screen.shown[key])
        print("\(label) | \(screen.name).\(key): model=\(model[key] ?? "-") ekran=\(screen.shown[key] ?? "-") -> \(result)")
        return result
    }
}

func countVerdicts(_ verdicts: [String]) {
    for name in ["uyumlu", "bayat", "eksik", "artik"] {
        print("\(name): \(verdicts.filter { $0 == name }.count)")
    }
}

Aynı Model, İki Ekran

Bir profil ekranı üç değer gösteriyor: ad, okunmamış sayısı ve durum. Model tek bir değer tipidir. Bildirimsel çerçevede ekran bu modelin bir işlevidir.

import SwiftUI

struct ProfileView: View {
    let model: ProfileModel

    var body: some View {
        VStack {
            Text(model.title)
            Text(String(model.unread))
            Text(model.status)
        }
    }
}

Buyurgan çerçevede aynı üç değeri kod, üç etikete tek tek yazar.

import UIKit

final class ProfileController: UIViewController {
    @IBOutlet private var titleLabel: UILabel!
    @IBOutlet private var unreadLabel: UILabel!
    @IBOutlet private var statusLabel: UILabel!

    func render(_ model: ProfileModel) {
        titleLabel.text = model.title
        unreadLabel.text = String(model.unread)
        statusLabel.text = model.status
    }
}

Model, kodun ekrana ne yazdığını kurar; çerçevenin kendisi değildir. İki ekranın yazdığı değerler yardımcı dosyada durur ve adlar KAYNAK parçalardakilerle aynıdır.

// Profile.swift — ayni modelden kurulan iki ekran
struct ProfileModel {
    var title: String
    var unread: Int
    var status: String

    var values: [String: String] {
        ["title": title, "unread": String(unread), "status": status]
    }
}

struct ProfileView {
    let model: ProfileModel

    func body(on screen: Screen) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
    }
}

final class ProfileController {
    let screen = Screen("ProfileController")

    func render(_ model: ProfileModel) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
    }
}

İlk olay: aynı model iki ekrana verilir.

// main.swift — ayni model iki ekrana yazilir
let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status"]

let declarative = Screen("ProfileView")
ProfileView(model: model).body(on: declarative)
let controller = ProfileController()
controller.render(model)

let viaDeclarative = check("ayni-model-bildirimsel", model: model.values, screen: declarative, keys: keys)
let viaImperative = check("ayni-model-buyurgan", model: model.values, screen: controller.screen, keys: keys)

countVerdicts(viaDeclarative + viaImperative)
ayni-model-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
ayni-model-bildirimsel | ProfileView.unread: model=3 ekran=3 -> uyumlu
ayni-model-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
ayni-model-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
ayni-model-buyurgan | ProfileController.unread: model=3 ekran=3 -> uyumlu
ayni-model-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
uyumlu: 6
bayat: 0
eksik: 0
artik: 0

Altı alanın altısı uyumlu. Buyurgan tarafta bunun sebebi kodun üç alanı da yazmasıdır; bildirimsel tarafta ise çerçevenin okuyanı yeniden hesaplamasıdır.

KP21. Model, bildirimsel görünümün body içinde yazdığı değerleri ekrana yazılmış kabul eder ve modelde yeniden hesaplamayı bodyyi yeniden çağırarak kurar. Çerçevenin hesabı ne zaman yaptığı ölçülmez; bu bir varsayımdır.

Buyurgan Tarafta Unutulan Alan

Aynı ekran buyurgan çerçevede yazılırken bir satırın düşmesi çok kolaydır. İki olay kuralım. Birincisinde denetleyici durum etiketini hiç yazmaz. İkincisinde ekran doğru kurulur, sonra model değişir ve değişimi gören kod ekranı yeniden yazmaz.

// main.swift — buyurgan denetleyici durumu unutur, sonra model degisir
final class ForgetfulProfileController {
    let screen = Screen("ForgetfulProfileController")

    func render(_ model: ProfileModel) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
    }
}

let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status"]

let forgetful = ForgetfulProfileController()
forgetful.render(model)
let declarative = Screen("ProfileView")
ProfileView(model: model).body(on: declarative)

let missingDeclarative = check("buyurgan-unuttu-bildirimsel", model: model.values, screen: declarative, keys: keys)
let missingImperative = check("buyurgan-unuttu-buyurgan", model: model.values, screen: forgetful.screen, keys: keys)

let latest = ProfileModel(title: "Ayse", unread: 5, status: "cevrimici")
let refreshed = Screen("ProfileView")
ProfileView(model: latest).body(on: refreshed)
let careful = ProfileController()
careful.render(model)

let changedDeclarative = check("model-degisti-bildirimsel", model: latest.values, screen: refreshed, keys: keys)
let changedImperative = check("model-degisti-buyurgan", model: latest.values, screen: careful.screen, keys: keys)

countVerdicts(missingDeclarative + missingImperative + changedDeclarative + changedImperative)
buyurgan-unuttu-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
buyurgan-unuttu-bildirimsel | ProfileView.unread: model=3 ekran=3 -> uyumlu
buyurgan-unuttu-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.title: model=Ayse ekran=Ayse -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.unread: model=3 ekran=3 -> uyumlu
buyurgan-unuttu-buyurgan | ForgetfulProfileController.status: model=cevrimici ekran=- -> eksik
model-degisti-bildirimsel | ProfileView.title: model=Ayse ekran=Ayse -> uyumlu
model-degisti-bildirimsel | ProfileView.unread: model=5 ekran=5 -> uyumlu
model-degisti-bildirimsel | ProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
model-degisti-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
model-degisti-buyurgan | ProfileController.unread: model=5 ekran=3 -> bayat
model-degisti-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
uyumlu: 10
bayat: 1
eksik: 1
artik: 0

Unutulan status alanı buyurgan ekranda eksik, güncellenmeyen unread alanı bayat çıktı; bildirimsel ekranın altı alanı uyumludur. Yani buyurgan çerçeve, programcının yazmayı unutabileceği yer sayısını artırır. Bu bir kusur değil, çerçevenin işi programcıya geri vermesinin bedelidir: ekran üzerindeki denetim de o kadar fazladır.

Sınırlayıcı Ölçüm

Bu bedel, uyumu bir seçim ölçütü yapmaz. Kural ekranı hangi çerçevenin kurduğunu bilmez; ekranın ne gösterdiğine bakar ve bozulma iki yönde de mümkündür. Titiz yazılmış bir buyurgan denetleyici tüm alanları uyumlu tutar. Bildirimsel bir görünüm ise modelde olmayan sabit bir metni gösterebilir; sabit metin her yeniden hesaplamada aynen yazılır.

// main.swift — bozulma iki cercevede de olur
struct BannerProfileView {
    let model: ProfileModel

    func body(on screen: Screen) {
        screen.set("title", model.title)
        screen.set("unread", String(model.unread))
        screen.set("status", model.status)
        screen.set("banner", "yeni")
    }
}

let model = ProfileModel(title: "Ayse", unread: 3, status: "cevrimici")
let keys = ["title", "unread", "status", "banner"]

let careful = ProfileController()
careful.render(model)
let banner = Screen("BannerProfileView")
BannerProfileView(model: model).body(on: banner)

let carefulResult = check("sinir-buyurgan", model: model.values, screen: careful.screen, keys: keys)
countVerdicts(carefulResult)
let bannerResult = check("sinir-bildirimsel", model: model.values, screen: banner, keys: keys)
countVerdicts(bannerResult)
sinir-buyurgan | ProfileController.title: model=Ayse ekran=Ayse -> uyumlu
sinir-buyurgan | ProfileController.unread: model=3 ekran=3 -> uyumlu
sinir-buyurgan | ProfileController.status: model=cevrimici ekran=cevrimici -> uyumlu
sinir-buyurgan | ProfileController.banner: model=- ekran=- -> olcum-disi
uyumlu: 3
bayat: 0
eksik: 0
artik: 0
sinir-bildirimsel | BannerProfileView.title: model=Ayse ekran=Ayse -> uyumlu
sinir-bildirimsel | BannerProfileView.unread: model=3 ekran=3 -> uyumlu
sinir-bildirimsel | BannerProfileView.status: model=cevrimici ekran=cevrimici -> uyumlu
sinir-bildirimsel | BannerProfileView.banner: model=- ekran=yeni -> artik
uyumlu: 3
bayat: 0
eksik: 0
artik: 1

Buyurgan ekran üç uyumlu verdi ve banner ölçüm dışında kaldı. Bildirimsel ekran aynı üç uyumluyu ve bir artık verdi. İlk bakışta iki ekrandan biri “daha uyumlu” görünür, ama iki çerçevenin sayısı birbirini sıralamaz: aynı kural, aynı model, kodun yazdığı farklı hatalar.

KP22. Model, ekranı kuran çerçeveyi bilmez; yalnız ekranın gösterdiği alanları karşılaştırır. Çerçeve seçiminin gerekçeleri ölçülmez, ve bu derste sayıya dökülmez.

Gerçek gerekçeler başka yerdedir ve hepsi düzyazıyla tartılır.

  • Ekip. Ekibin bildirimsel çerçeveyi bilmesi, ekran başına yazılan satırın azalması demektir; ekip buyurgan çerçeveyi biliyorsa öğrenme maliyeti yeni çerçevenin getirdiği kazancı aşabilir.
  • Eski kod. Çalışan bir ekranı yeniden yazmak, risk taşır. Önceki dersteki kademeli yol, bu riski ekran başına küçültür.
  • Platform sürümü. Bildirimsel çerçeve her hedef sürümde bulunmaz; desteklenecek en düşük sürüm çerçeveyi seçmeden önce belirlenir.
  • Özel çizim. Elle çizilen ya da katman animasyonlu bir parça, buyurgan çerçevenin sunduğu denetime ihtiyaç duyabilir; bildirimsel ekran onu sarmalayarak alır.

Bu dört gerekçeden hiçbiri bir sayı değildir, ve ölçümümüz bu kararı vermeye yetmez.

Özet

  • Aynı model iki çerçeveyle kurulunca iki ekran da altı alanda uyumludur (6 uyumlu).
  • Buyurgan tarafta yazılmayan alan eksik, modeli izlemeyen alan bayat ölçülür; bildirimsel taraf aynı olaylarda uyumludur (10 uyumlu, 1 bayat, 1 eksik).
  • Bozulma iki çerçevede de olur: bildirimsel ekranın modelde olmayan sabit metni artık verir (3 uyumlu, 1 artık).
  • Uyum bir çerçeve seçim ölçütü değildir; seçim ekip, eski kod, platform sürümü ve özel çizim üzerinden düzyazıyla tartılır.
  • Bu dersin uyumu: uyumlu.

Kurs Kapanışı

Kurs, tek bir soruyla on beş dersi ölçtü: bu ekran modelle uyuşuyor mu? Her dersin olayı, uyumu ve sınırlayıcı ölçümü aşağıdadır. Uyum hücreleri kaynak dersin özetinden alınmıştır.

Ders Olay Uyum Sınırlayıcı ölçüm
Görünüm Denetleyicisi Kavramı yükleme, okundu işareti, klasör değişimi, taslak gelişi, hücre yeniden kullanımı dördü (3/2/2/2) biçimlenmiş metin eşit sayılmaz; iki tarafta olmayan alan sayılmaz
Yaşam Döngüsü Yöntemleri yalnız yüklemede yazılan değer, model altta değişir bayat çağrı sırasını model kurar, çerçeve değil
Gezinme Denetleyicileri itme ve geri çıkarma, kalkan seçimin vurgusu artık çıkarılan ekran ölçüm dışı
Sunum Biçimleri kip sunulan not, sunan ekranın yazmadığı alan eksik yalnız görünür ekrana bakılır
Görsel Düzenleyici ve Kodla Arayüz kopuk bağlantı, yer tutucu metin bayat yer tutucu kodun yazmadığı etikette kalır
Bağlantılar ve Eylemler modeli yazıp etiketi yazmayan eylem bayat biçimlenmiş metin ham değerle bayat çıkar
Kısıt Tabanlı Düzen güncellenmeyen kısıt sabiti bayat öncelik ve belirsizlik modelde yok
Yığıt Görünümleri gizlenmeyen alt görünüm artık gizleme ile kaldırma aynı değeri yazar
Tablo Görünümleri yeniden kullanılan hücrede kalan ek artık kuyruk boyutu ölçülmez
Koleksiyon Görünümleri eklenip bildirilmeyen öğe eksik konum hesabı ölçülmez
Temsilci Kalıbı bağlanmamış temsilci bayat unutan kişi okunmaz
Çizim ve Katman Animasyonu istenmeyen yeniden çizim bayat animasyon süresi ölçülmez
Bildirimsel ve Buyurgan Arayüz Bir Arada atanmayan kök görünüm bayat bildirimsel yeniden hesap varsayım
Eski Kodun Kademeli Dönüşümü taşınmayan alan, kalkan rozet eksik ekran düzeyinde tek yanıt yok
Çerçeve Seçimi aynı model, unutulan alan uyumlu uyum seçim ölçütü değil

Açılış dersi dışındaki on dört dersin dağılımı: 1 uyumlu, 7 bayat, 3 eksik, 3 artık. Çekirdeğin 3/2/2/2 dağılımı ayrı bir sayımdır: çekirdek açılış dersindeki dokuz alanı sayar, dağılım ise on dört dersin uyumunu sayar; ikisi aynı şey değildir.

Sıradaki kurs (M30/K05) verinin saklanmasını, ağ isteklerini ve eşzamanlılığı konu alır. Bu kursun ölçü ekseni orada sürmez; K05 kendi sorusunu kendisi sorar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ ↵ Esc gezin · aç · kapat