İçeriğe geç
academia.sh

Ders 06 / 10

Yaklaşım Seçim Ölçütleri

Yaklaşım seçimi özelliklerin platforma bağımlılığına bakar. Ders aynı altı özelliği tek kod tabanı ve paylaşılan mantık ile yerel arayüz düzenekleriyle ölçer, dört paylaşımın iki dağılımını karşılaştırır ve sayının yaklaşımı tek başına seçmediğini gösterir.

Yayın Güncelleme

Bu derste

  • Yaklaşım seçiminin özelliklerin platforma bağımlılığıyla başladığını açıklar
  • Yalnız bir platformda bulunan bir özelliğin hangi yaklaşımda olursa olsun tek çıktığını ölçer
  • Aynı altı özelliğin iki düzenekte nasıl farklı dağıldığını karşılaştırır
  • Paylaşım sayılarının tek başına yaklaşım seçmediğini, bedelin düzyazıda tartılması gerektiğini gösterir
İçindekiler

Beş ders beş düzeneği tek tek ölçtü. Her düzeneğin bir paylaşımı çıktı: sayfa ortak, köprü dallı, çizim motoru ortak, arayüzü ayrı yazılan düzenek ikiz. Gerçek bir uygulamada ise tek bir özellik yoktur. Bir liste vardır ve listenin her satırı kendi paylaşımını taşır. Yaklaşım seçimi bu listenin ne kadarının hangi paylaşıma düştüğüne bakar.

Kursun sorusu değişmez: bu özelliğin kodu platformlar arasında nasıl paylaşılıyor? Bu derste soru aynı altı özelliğe iki düzenekte sorulur ve iki dağılım yan yana konur. Ders bir yaklaşımı önermez. Önerinin neye dayanması gerektiğini gösterir.

Seçimin ilk girdisi, özelliğin platforma ne kadar bağlı olduğudur. Fiyat biçimi platformu hiç okumaz. Başlık kısaltma, yazı alanının genişliğine göre platformdan etkilenir. Gezinme çubuğu platformun kendi alışkanlığına uyar. Biyometrik giriş platformun kendi programlama arayüzünü çağırır. Bir ana ekran parçası ise bu uygulamada yalnız bir platform için yazılır. Altı özellik, platforma bağımlılığın altı farklı derecesidir.

YA1. Model, bu paylaşımın kuralını kurar; model bir uygulamayı derlemez, bir ekranı çizmez ve bir platformun programlama arayüzünü çağırmaz. Altı özellik modelde sabit bir listedir. Uygulamada “ana ekran parçası” yalnız iOS için vardır; Android karşılığı bu uygulamanın kapsamında değildir. Bu bir varsayımdır ve gerçek bir ürün kararı değildir.

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

Altı özelliğin işlevlerini ortak bir dosyaya koyuyoruz. Sonraki iki ölçüm onları farklı düzeneklerle birleştirir.

// catalog.mjs — alti ozelligin islevleri
export function priceText(cents) {
  const pad = String(cents % 100).padStart(2, "0");
  return `${Math.floor(cents / 100)}.${pad}`;
}

export function cartSum(lines) {
  return lines.reduce((sum, [price, qty]) => sum + price * qty, 0);
}

export function titleCut(title, platform) {
  const limit = platform === "ios" ? 10 : 8;
  return title.length > limit ? `${title.slice(0, limit - 1)}~` : title;
}

export function backBar(screen, platform) {
  return `${screen}:${platform === "ios" ? "sol" : "alt"}-geri`;
}

export const iosBiometric = (user) => `yuz:${user}`;
export const androidBiometric = (user) => `parmak:${user}`;
export const iosTile = (name) => `parca:${name}`;

titleCut ve backBar platform bağımsız yazılmıştır ama platform adını okurlar. Bu iki işlev ölçümde tek işlev olarak durur. Biyometrik girişin iki işlevi ve ana ekran parçasının tek işlevi ayrı ayrı adlandırılmıştır.

Tek Olan Özellik

İlk ölçümde iki uçtaki özelliği koyuyoruz: platforma hiç bağlı olmayan fiyat biçimi ve bu uygulamada yalnız bir platform için yazılan ana ekran parçası. İlki ortak çıkacaktır. İkincisi için Android uygulaması yoktur ve impl içinde yalnız ios anahtarı bulunur.

// main.mjs
import { Sharing, countSharing } from "./sharing.mjs";
import { priceText, iosTile } from "./catalog.mjs";

const prices = [1250, 300, 99999, 5];
const tiles = ["gunluk", "haftalik"];

const features = [
  new Sharing("fiyat-bicimi", { ios: priceText, android: priceText }, prices),
  new Sharing("ana-ekran-parcasi", { ios: iosTile }, tiles),
];
features.forEach((f) => f.line());
countSharing(features);
fiyat-bicimi: kod=1 | fark=0/4 -> ortak
ana-ekran-parcasi: kod=1 | eksik=android -> tek
ortak: 1
dalli: 0
ikiz: 0
tek: 1

fiyat-bicimi için fark=0/4 ve kod=1 çıktı: bu özellik bir kez yazılır ve iki platformda aynı sonucu verir. ana-ekran-parcasi için fark yerine eksik=android okunur ve paylaşım tektir. Tek olan bir özellikte karşılaştırılacak ikinci bir uygulama yoktur, bu yüzden fark hesaplanmaz. Hangi yaklaşım seçilirse seçilsin bu özellik tek kalır, çünkü eksik olan şey kodun düzeneği değil, öbür platformdaki uygulamanın kendisidir.

Yalnız iOS’ta bulunan bir özelliğin kaynağı şöyle görünür. Parça ölçülmez.

// Platform kodu: HomeTile
import WidgetKit
import SwiftUI

struct HomeTile: Widget {
    var body: some WidgetConfiguration {
        StaticConfiguration(kind: "home-tile", provider: TileProvider()) { entry in
            Text(entry.title)
        }
    }
}

Bu, kapsam kararıyla tek platformda kalan bir özelliktir. Hiçbir ortak katman, öbür platformda yazılmamış bir uygulamayı kendiliğinden ortaya çıkarmaz. Seçimin ikinci girdisi buradan çıkar: hangi özellikler yalnız bir platform için yazılıyor? Bu özellikler yaklaşım karşılaştırmasının dışında tutulur, çünkü yaklaşımlar arasında farkları yoktur.

Tek Kod Tabanında Altı Özellik

İkinci ölçümde altı özelliği tek kod tabanı düzeneğiyle ölçüyoruz. Bu düzenekte her özellik mümkün olduğunca tek işlevle yazılır; platforma bağımlı kısımlar işlevin içinde platform anahtarıyla ayrılır. İstisna, biyometrik girişin platform programlama arayüzünü çağırması ve ana ekran parçasının tek platformda bulunmasıdır.

YA2. Modelde “tek kod tabanı” şu anlama gelir: platforma duyarlı özellikler tek işlev olarak kalır, platform bağımsız değişkenini okur. Biyometrik giriş bu düzenekte bile iki ayrı işlev ister, çünkü iki platformun programlama arayüzü ortak değildir. Bu model bir kabuk bir köprüyü ya da bir motoru taklit etmez; yalnız işlevlerin sayısını sayar.

// main.mjs
import { Sharing, countSharing } from "./sharing.mjs";
import {
  priceText, cartSum, titleCut, backBar, iosBiometric, androidBiometric, iosTile,
} from "./catalog.mjs";

const prices = [1250, 300, 99999, 5];
const carts = [[[100, 2], [250, 1]], [[999, 3]], [[50, 4], [75, 2]]];
const titles = ["Kahve", "Cay kahve", "Haftalik plan", "Su"];
const screens = ["liste", "detay", "sepet"];
const users = ["ada", "can", "eda"];
const tiles = ["gunluk", "haftalik"];

const features = [
  new Sharing("fiyat-bicimi", { ios: priceText, android: priceText }, prices),
  new Sharing("sepet-toplami", { ios: cartSum, android: cartSum }, carts),
  new Sharing("baslik-kisaltma", { ios: titleCut, android: titleCut }, titles),
  new Sharing("gezinme-cubugu", { ios: backBar, android: backBar }, screens),
  new Sharing("biyometrik-giris", { ios: iosBiometric, android: androidBiometric }, users),
  new Sharing("ana-ekran-parcasi", { ios: iosTile }, tiles),
];
features.forEach((f) => f.line());
countSharing(features);
fiyat-bicimi: kod=1 | fark=0/4 -> ortak
sepet-toplami: kod=1 | fark=0/3 -> ortak
baslik-kisaltma: kod=1 | fark=2/4 -> dalli
gezinme-cubugu: kod=1 | fark=3/3 -> dalli
biyometrik-giris: kod=2 | fark=3/3 -> ikiz
ana-ekran-parcasi: kod=1 | eksik=android -> tek
ortak: 2
dalli: 2
ikiz: 1
tek: 1

Dağılım iki ortak, iki dallı, bir ikiz ve bir tektir. İlk iki özellik platformu hiç okumadığı için ortaktır. baslik-kisaltma ve gezinme-cubugu tek işlevdir ama platform anahtarını okur; dallı çıkmalarının sebebi budur. baslik-kisaltma için fark=2/4 okunur: dört başlığın ikisinde iki platform farklı kısaltma üretti, çünkü iOS’ta yer on karakter, Android’de sekiz karakterdir. Bu iki sayı modelin girdisidir ve gerçek bir yazı alanının ölçüsü değildir. biyometrik-giris ikiz çıktı, çünkü iki platform iki ayrı programlama arayüzünü çağırır ve bu çağrıyı yazan iki kod vardır.

Bu dağılım, tek kod tabanının vaadinin hem gücünü hem sınırını gösterir. Altı özelliğin dördü tek işlevle yazıldı, ama dördünün ikisi hâlâ dallı. Tek işlev olmak, tek davranış olmak demek değildir.

Paylaşılan Mantık ve Yerel Arayüzle Altı Özellik

Üçüncü ölçümde aynı listeyi öteki düzenekle ölçüyoruz. Bu düzenekte iş kuralları ortak modülde kalır: fiyat biçimi ve sepet toplamı. Başlık, gezinme çubuğu ve biyometrik giriş arayüz katmanına aittir ve her platformda ayrı bir işlev olarak yazılır.

YA3. Modelde arayüz işlevleri ortak işlevi platform adıyla sarar: iosTitle ve androidTitle aynı kısaltma kuralını kendi platform adıyla çağırır, iosBack ve androidBack aynı gezinme kuralını. İki sarmalayıcı ayrı işlev nesneleridir; bu, ikinin ayrı yazıldığını temsil eder. Gerçek ekiplerde iki arayüz işlevi ortak bir kuralı sarmak zorunda değildir ve çoğunlukla sarmaz.

// main.mjs
import { Sharing, countSharing } from "./sharing.mjs";
import {
  priceText, cartSum, titleCut, backBar, iosBiometric, androidBiometric, iosTile,
} from "./catalog.mjs";

const iosTitle = (title) => titleCut(title, "ios");
const androidTitle = (title) => titleCut(title, "android");
const iosBack = (screen) => backBar(screen, "ios");
const androidBack = (screen) => backBar(screen, "android");

const prices = [1250, 300, 99999, 5];
const carts = [[[100, 2], [250, 1]], [[999, 3]], [[50, 4], [75, 2]]];
const titles = ["Kahve", "Cay kahve", "Haftalik plan", "Su"];
const screens = ["liste", "detay", "sepet"];
const users = ["ada", "can", "eda"];
const tiles = ["gunluk", "haftalik"];

const features = [
  new Sharing("fiyat-bicimi", { ios: priceText, android: priceText }, prices),
  new Sharing("sepet-toplami", { ios: cartSum, android: cartSum }, carts),
  new Sharing("baslik-kisaltma", { ios: iosTitle, android: androidTitle }, titles),
  new Sharing("gezinme-cubugu", { ios: iosBack, android: androidBack }, screens),
  new Sharing("biyometrik-giris", { ios: iosBiometric, android: androidBiometric }, users),
  new Sharing("ana-ekran-parcasi", { ios: iosTile }, tiles),
];
features.forEach((f) => f.line());
countSharing(features);
fiyat-bicimi: kod=1 | fark=0/4 -> ortak
sepet-toplami: kod=1 | fark=0/3 -> ortak
baslik-kisaltma: kod=2 | fark=2/4 -> ikiz
gezinme-cubugu: kod=2 | fark=3/3 -> ikiz
biyometrik-giris: kod=2 | fark=3/3 -> ikiz
ana-ekran-parcasi: kod=1 | eksik=android -> tek
ortak: 2
dalli: 0
ikiz: 3
tek: 1

Dağılım iki ortak, sıfır dallı, üç ikiz ve bir tek oldu. İlk ölçümde dallı olan iki özellik burada ikize döndü: sonuçları değişmedi, fark=2/4 ve fark=3/3 aynı kaldı, ama her platformun kendi işlevi olduğu için kod sayısı ikiye çıktı. Ortak sayısı ve tek sayısı değişmedi. Altı özelliğin yarısı bu düzenekte iki kez yazılmıştır.

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

İki dağılımı yan yana koyunca bir sonuç çıkarmak çekicidir: ilkinde iki dallı ve bir ikiz var, ikincisinde sıfır dallı ve üç ikiz var; öyleyse biri öteki kadar iyi ya da kötü. Kural bunu söyleyemez. Sayılar iki düzeneğin altı özellik üzerindeki paylaşımını verir. Hangisinin daha az bakım isteyeceğini, hangisinin daha az hataya yol açacağını ya da hangisinin kullanıcıya daha iyi göründüğünü vermez.

Dallı bir özellik tek işlevdir ama içinde bir dal vardır; dalın iki kolu da bakım ister ve kolların ayrışması izlenmelidir. İkiz bir özellik iki işlevdir ve ikisi de bakım ister. Hangisi daha pahalıdır sorusunun yanıtı, özelliğin ne sıklıkla değiştiğine ve değişikliğin iki platforma birlikte gidip gitmediğine bağlıdır. Kural bu bilgiyi görmez; yalnız kodun yapısını görür.

Seçim bu yüzden en az dört girdiye bakar ve ölçüm yalnız ilkine yardım eder:

  • Özelliklerin hangi paylaşıma düştüğü. Bu dersin ölçtüğü şey budur.
  • Yalnız bir platformda var olan özelliklerin payı. Bunlar her düzenekte tek kalır.
  • Ekibin hangi kod tabanlarını bakımını sürdürebileceği. Bu bir ölçüm değil bir kapasite sorusudur.
  • Uygulamanın platformun kendi görünümüne ve alışkanlıklarına ne kadar uyması gerektiği. Bu bir paylaşım sorusu değil bir ürün sorusudur.

İlk girdi ölçülür, ötekiler konuşulur. Hiçbir yaklaşım ilk girdiden tek başına seçilmez. Ölçüm seçime bir zemin verir ve sayıların nerede yanıltabileceğini düzyazı söyler.

Özet

  • Bu dersin paylaşımı: tek, bir özellik için; dersin taşıyıcı ölçümü aynı altı özelliğin iki düzenekteki dağılımıdır. Ana ekran parçası yalnız bir platform için yazıldığından hangi düzenek seçilirse seçilsin tek kalır.
  • Tek kod tabanı düzeneğinde altı özellik iki ortak, iki dallı, bir ikiz ve bir tek olarak dağıldı.
  • Paylaşılan mantık ve yerel arayüz düzeneğinde aynı altı özellik iki ortak, sıfır dallı, üç ikiz ve bir tek olarak dağıldı; dallı iki özellik ikize döndü.
  • Kural kodun yapısını sayar, bedelini sayamaz: hangi dağılımın daha az bakım isteyeceği özelliğin değişme sıklığına ve ekibin kapasitesine bağlıdır.
  • Yaklaşım seçimi en az dört girdiye bakar: paylaşım dağılımı, yalnız bir platformda bulunan özellikler, ekibin bakım kapasitesi ve ürünün platformun görünümüne uyma ihtiyacı.

Sonraki Adım

Bu kurs yaklaşımların kodu nasıl paylaştırdığını ölçtü. Sıradaki kurs, Platform Tasarım Dilleri Farkı, paylaşımın sınırını başka bir yerden çizer: aynı kod iki platformda çalışsa bile kullanıcının beklediği görünüm ve davranış platforma göre ayrışabilir.

İ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