İçeriğe geç
academia.sh

Ders 05 / 14

Çevrimdışı Öncelikli Tasarım

Çevrimdışı öncelikli tasarım, yerel veriyi doğruluk kaynağı yapar ve ağı yalnız tazeleme için kullanır. Ders aynı akışı iki tasarımla kurar ve ağ yokken hangisinin ne kadar çalıştığını ölçer.

Yayın Güncelleme

Bu derste

  • Yerel veriyi doğruluk kaynağı yapan tasarımla ağ öncelikli tasarımı karşılaştırır
  • Ağın yalnız tazeleme için kullanıldığı okuma yolunu açıklar
  • Aynı akışın iki tasarımla ağ yokken kapalı ve kısıtlı çıkışını ölçer
  • Yerel modelle tam uyuşan bir ekranın neden yine de kısıtlı olduğunu açıklar
İçindekiler

Önceki konu, ortak kodun nasıl dilimlendiğini ve her platformun kendi katmanını nasıl taşıdığını ölçtü. Bu konu bir uygulamanın en sık karşılaştığı koşula iner: ağ yok. Metroda, asansörde, uçakta ya da kapsama alanının dışında uygulama yine açılır ve kullanıcı yine bir şey bekler. Bu derste bu beklentiyi karşılamanın iki tasarımı yan yana konur.

Kursun sorusu aynı kalır: bu koşulda bu özellik ne kadar çalışıyor? Açılış dersindeki dokuz kayıt beş tam, bir kısıtlı, iki ertelenen ve bir kapalı çıkmıştı. Bu ders o sayıyı değiştirmez; yalnız kendi kesitini ölçer.

İki Tasarım

Ağ öncelikli bir tasarımda ekran her açılışta veriyi sunucudan ister ve gelen yanıtı gösterir. Doğruluk kaynağı sunucudur; yerel depo en fazla bir önbellektir. Ağ varken bu tasarım basit ve doğrudur. Ağ yokken ekranın gösterecek bir şeyi kalmaz.

Çevrimdışı öncelikli bir tasarımda doğruluk kaynağı yereldir. Ekran her zaman yerel depodan okur. Ağ okumanın yolu değildir; yalnız yerel depoyu tazelemenin yoludur. Sunucudan gelen yeni kayıtlar yerel depoya yazılır ve ekran yerel depodaki değişikliği gösterir. Ağ gidince ekranın okuduğu şey değişmez, yalnız tazelenmez.

Bu ayrım bir kuraldır, bir kütüphane seçimi değildir. Aynı gömülü veritabanı iki tasarımda da bulunabilir. Fark, ekranın okuma yolunun nereden geçtiğidir. Aşağıdaki Android parçası çevrimdışı öncelikli okuma yolunu gösterir. Parça ölçülmez.

// Platform kodu: Android yerel okuma
class FeedRepository(private val db: SQLiteDatabase) {
    fun readPosts(): List<Post> {
        val cursor = db.query("posts", null, null, null, null, null, "published DESC")
        return cursor.use { rows ->
            generateSequence { if (rows.moveToNext()) rows.toPost() else null }.toList()
        }
    }
}

Ekran depoyu çağırır, ağı çağırmaz. Tazeleme ayrı bir iştir: ağdan gelen kayıtlar posts tablosuna yazılır ve okuma yolu bir sonraki okumada onları görür. iOS tarafında aynı sözleşme Swift’te aynı biçimde kurulur; yerel depodan okuyan bir katman ve ağdan tazeleyen ayrı bir katman vardır.

Özellikleri Kurmak

İki tasarımı ölçmek için kursun çekirdeğine ihtiyaç var. Çekirdek ilk dersten tanıdıktır ve her derste aynı biçimde yeniden verilir; ders ona dokunmaz.

// 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}`);
}

Çekirdeğin ardından dersin yardımcı dosyası gelir. Akış için iki özellik kurulur. FeedRemote ağ öncelikli akıştır: yalnız network ister ve yedeği yoktur. FeedLocal çevrimdışı öncelikli akıştır: storage ve network ister, ağ eksik olduğunda kisitli yedeğine düşer. Üçüncü özellik Bookmarks yer imleridir ve yalnız storage ister. stateOf(link) bir bağlantı durumundan koşul üretir: ağ varsa network, depolama alanı varsa storage yeteneği koşula girer.

// feeds.mjs — iki akis tasarimini ve baglanti durumlarini kurar
import { feature, condition } from "./operability.mjs";

export const remoteFeed = feature("FeedRemote", ["network"]);
export const localFeed = feature("FeedLocal", ["storage", "network"], { network: "kisitli" });
export const bookmarks = feature("Bookmarks", ["storage"]);

export function stateOf(link) {
  const has = [];
  if (link.network) has.push("network");
  if (link.storage !== false) has.push("storage");
  return condition(link.name, has);
}

Ağ Yokken İki Tasarım

İlk ölçüm iki akışı iki bağlantı durumunda koşar. online durumunda ağ ve depolama alanı vardır. offline durumunda yalnız depolama alanı vardır.

// main.mjs
import { assess, printLevels } from "./operability.mjs";
import { remoteFeed, localFeed, stateOf } from "./feeds.mjs";

const links = [
  { name: "online", network: true },
  { name: "offline", network: false },
];
printLevels(assess([remoteFeed, localFeed], links.map(stateOf)));
tam: FeedRemote @ online eksik=-
tam: FeedLocal @ online eksik=-
kapali: FeedRemote @ offline eksik=network
kisitli: FeedLocal @ offline eksik=network

Ağ varken iki tasarım da tamdır; fark ağ gidince açılır. FeedRemote @ offline kapalıdır, çünkü eksik network yeteneğinin yedeği yoktur. FeedLocal @ offline kısıtlıdır, çünkü aynı eksik için özellik bir yedek tanımlamıştır: yerel veriyle çalışmaya devam eder. İki özellik aynı eksiği taşır ve yedek yüzünden farklı düzeye düşer.

CE1. Model, ağı tek bir yetenek olarak kurar: ya vardır ya yoktur. Gerçek bir bağlantı kesintili, yavaş ya da yarı açık olabilir; bu durumlar dördüncü derste ayrıca ele alınır. Kural yeteneği ve yedeği görür; yerel depoda kaç kayıt bulunduğunu, kayıtların ne kadar eski olduğunu ve kullanıcının ne beklediğini görmez. Model, bu işlerliğin kuralını kurar; model çerçevenin kendisi değildir.

Okuma Yolu ve Tazeleme

İşlerlik kaydı ekranın ne gösterdiğini söylemez. Bunu görmek için iki akışın okuma yolu ayrıca modellenir. Depoda üç yerel kayıt vardır; sunucuda dört kayıt vardır ve ikisi yerel kayıtlarla ortaktır. Ağ öncelikli akış yalnız sunucudan okur. Çevrimdışı öncelikli akış yerelden okur ve ağ varsa sunucudaki yeni kayıtları ekler.

// reader.mjs — iki tasarimin gonderi okuma yolunu kurar
export function readFeed(design, store, link) {
  if (design === "remote") {
    return link.network ? { shown: store.remote.length, fresh: true } : { shown: 0, fresh: false };
  }
  const merged = link.network ? [...new Set([...store.local, ...store.remote])] : store.local;
  return { shown: merged.length, fresh: link.network };
}

export function printReads(label, design, store, links) {
  for (const link of links) {
    const read = readFeed(design, store, link);
    console.log(`${label} @ ${link.name}: ${read.shown} gonderi, taze=${read.fresh ? "evet" : "hayir"}`);
  }
}

Ölçüm iki okumayı ve offline koşulunun işlerlik kayıtlarını birlikte basar.

// main.mjs
import { assess, printLevels } from "./operability.mjs";
import { remoteFeed, localFeed, stateOf } from "./feeds.mjs";
import { printReads } from "./reader.mjs";

const store = { local: ["p1", "p2", "p3"], remote: ["p2", "p3", "p4", "p5"] };
const links = [
  { name: "online", network: true },
  { name: "offline", network: false },
];
printReads("FeedRemote", "remote", store, links);
printReads("FeedLocal", "local", store, links);
const records = assess([remoteFeed, localFeed], links.map(stateOf));
printLevels(records.filter((r) => r.condition === "offline"));
FeedRemote @ online: 4 gonderi, taze=evet
FeedRemote @ offline: 0 gonderi, taze=hayir
FeedLocal @ online: 5 gonderi, taze=evet
FeedLocal @ offline: 3 gonderi, taze=hayir
kapali: FeedRemote @ offline eksik=network
kisitli: FeedLocal @ offline eksik=network

Ağ varken çevrimdışı öncelikli akış beş gönderi gösterir: üç yerel ve sunucudan gelen iki yeni kayıt. Ağ yokken üç yerel gönderiyi göstermeye devam eder ve tazelik düşer. Ağ öncelikli akış ağ yokken sıfır gönderi gösterir. İki tasarımın işlerlik kayıtları, okuma yolunun bu farkını sınıfa çevirir: sıfır gönderi kapalı, üç gönderi kısıtlı.

Depolama Alanı Doğruluk Kaynağıdır

Yerel veriyi doğruluk kaynağı yapan tasarım ağa olan bağımlılığı azaltır ve depolama alanına olan bağımlılığı artırır. Depolama alanı dolduğunda yerel okuma da yazma da çalışmaz. Üçüncü ölçüm bunu storage-full koşuluyla gösterir: ağ vardır, depolama alanı yoktur.

// main.mjs
import { assess, printLevels } from "./operability.mjs";
import { localFeed, bookmarks, stateOf } from "./feeds.mjs";

const links = [
  { name: "online", network: true },
  { name: "offline", network: false },
  { name: "storage-full", network: true, storage: false },
];
printLevels(assess([localFeed, bookmarks], links.map(stateOf)));
tam: FeedLocal @ online eksik=-
tam: Bookmarks @ online eksik=-
kisitli: FeedLocal @ offline eksik=network
tam: Bookmarks @ offline eksik=-
kapali: FeedLocal @ storage-full eksik=storage
kapali: Bookmarks @ storage-full eksik=storage

Bookmarks yalnız yerel depoya dayanır, bu yüzden ağ gidince etkilenmez ve storage-full koşulunda kapanır. FeedLocal ağ eksikliğine yedekle dayanır ama depolama eksikliğine dayanamaz: storage için bir yedek tanımlanmamıştır, bu yüzden aynı özellik storage-full koşulunda kapalıdır. Çevrimdışı öncelikli tasarım ağ bağımlılığını yedekle karşılar; bağımlılığı ortadan kaldırmaz, yerel depoya taşır.

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

Bu dersin odak kaydı FeedLocal @ offline’dır. Son ölçüm üç özelliği iki durumda koşar, offline koşulunun kayıtlarını ve sayımı basar, ardından ekranın yerel modelle uyuşup uyuşmadığını sorar.

// main.mjs
import { assess, printLevels, countLevels } from "./operability.mjs";
import { remoteFeed, localFeed, bookmarks, stateOf } from "./feeds.mjs";
import { readFeed } from "./reader.mjs";

const store = { local: ["p1", "p2", "p3"], remote: ["p2", "p3", "p4", "p5"] };
const offline = { name: "offline", network: false };
const links = [{ name: "online", network: true }, offline];
const records = assess([remoteFeed, localFeed, bookmarks], links.map(stateOf));
printLevels(records.filter((r) => r.condition === "offline"));
countLevels(records);
const shown = readFeed("local", store, offline).shown;
console.log(`ekran yerel modelle uyusur: ${shown === store.local.length ? "evet" : "hayir"}`);
kapali: FeedRemote @ offline eksik=network
kisitli: FeedLocal @ offline eksik=network
tam: Bookmarks @ offline eksik=-
tam: 4
kisitli: 1
ertelenen: 0
kapali: 1
etkilenen: 2
ekran yerel modelle uyusur: evet

İlk iki satır dersin işlerliğini taşır: aynı akış ağ öncelikli kurulduğunda kapalı, çevrimdışı öncelikli kurulduğunda kısıtlı çıktı. Altı kaydın dördü tam, biri kısıtlı, biri kapalıdır; etkilenen iki.

Son satır işlerliğin neyi sınıflamadığını gösterir. M30/K04’te bir ekranın modelle uyuşup uyuşmadığı soruldu. Burada ekran yerel modelle tam uyuşur: gösterdiği üç gönderi yerel depodaki üç gönderidir ve ekran ile model arasında bir ayrılık yoktur. Yine de FeedLocal @ offline tam değil, kısıtlıdır. Uyum ile işlerlik ayrı eksenlerdir. Uyum ekranın modelin söylediğini gösterip göstermediğini sorar; işlerlik özelliğin o koşulda vaat ettiğinin ne kadarını yaptığını sınıflar. Yeni içerik gelmeyen bir akış, modeliyle tam uyuşsa da, ağ varken olduğundan daha azını yapar.

Bu fark tasarım kararını da etkiler. Çevrimdışı öncelikli bir ekran için “çevrimdışı çalışıyor” demek yetmez; hangi işlerin yedekle sürdüğünü ve hangilerinin durduğunu özellik özellik söylemek gerekir.

Özet

  • Bu dersin işlerliği: kısıtlı. FeedLocal @ offline, network eksik olduğu ve kisitli yedeği tanımlandığı için kısıtlı çıktı; ağ öncelikli FeedRemote aynı koşulda yedeksiz olduğundan kapalı kaldı.
  • Çevrimdışı öncelikli tasarımda doğruluk kaynağı yerel depodur; ağ okumanın yolu değil, yerel depoyu tazelemenin yoludur.
  • Ağ varken iki tasarım da tamdı. Ağ yokken okuma yolu farkı gösterdi: ağ öncelikli akış sıfır gönderi, çevrimdışı öncelikli akış üç gönderi gösterdi.
  • Yerel veri ağ bağımlılığını yedekle karşılar ama depolama bağımlılığını kaldırmaz: storage-full koşulunda FeedLocal kapalıdır.
  • Ekran yerel modelle tam uyuşsa da özellik kısıtlı kalır; uyum ve işlerlik ayrı eksenlerdir.

Sonraki Adım

Bu derste ağ yokken yalnız okuma ele alındı: yerel veri gösterildi, kullanıcının yaptığı değişiklik ise hiç konuşulmadı. Sıradaki ders, Eşitleme Stratejileri, çevrimdışıyken yapılan bir yazmanın kuyruğa alınmasını, ağ dönünce sunucuya gönderilmesini ve iki tarafın aynı kaydı değiştirdiği çakışmanın nasıl çözüldüğünü ele alır. Sonra çevrimdışı not düzenlemesinin ne kadar çalıştığını ölçer.

İ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