Ders 01 / 10
Çapraz Platform Gerekçesi
Çapraz platform geliştirmenin gerekçesi, aynı özelliğin iki platformda kaç ayrı kodla yazıldığıdır. Ders bir özelliğin kodunun paylaşımını dört yanıtla sınıflar: ortak, dallı, ikiz, tek.
Yayın Güncelleme
Bu derste
- Bir özelliğin kodunun iki platform arasındaki paylaşımını ortak, dallı, ikiz ve tek olarak sınıflar
- İki ayrı kod tabanının bedelini ve tek kod tabanının vaadini açıklar
- Girdisinden bağımsız sabit değer döndüren işlevin neden her zaman ortak çıktığını gösterir
- Aynı işlevin örnek listesine göre ortaktan dallıya geçebildiğini ölçer
İçindekiler
Önceki iki kurs dizisi bir uygulamayı iki kez baştan sona kurdu: biri bir platform için, öteki öteki platform için. İki dizi yan yana okununca aynı özelliklerin iki kez yazıldığı görülür. Fiyatı biçimleyen işlev, bir izni isteyen çağrı, geri düğmesine verilen yanıt her iki kod tabanında da var. Bu kursun konusu bu tekrarın nedeni, bedeli ve onu azaltmak için öne sürülen yollardır.
Kursun tek sorusu bu dersten başlar: bu özelliğin kodu platformlar arasında nasıl paylaşılıyor? Yanıtın dört biçimi var ve kurs boyunca adları değişmez. Özellik iki platformda aynı kodla çalışıyor ve kod her örnekte iki platformda aynı sonucu veriyorsa paylaşım ortaktır. Aynı kod çalışıyor ama kod en az bir örnekte platforma göre farklı sonuç veriyorsa paylaşım dallıdır. Her platformun kendi kodu varsa, sonuçlar aynı olsa bile, paylaşım ikizdir. Özelliğin kodu platformlardan birinde hiç yoksa paylaşım tektir. Dört yanıtın üst adı paylaşımdır; bir özelliğin paylaşımı denince bu dörtten biri anlaşılır.
Bu soru, M13/K04’te sorduğumuz “bu sonucu ne belirliyor” sorusuna benzer ama aynı değildir. Orada platform sonucu belirleyen bir ortamdı ve ölçülen şey sonucun kaynağıydı. Burada sonucun kaynağı sorulmaz: aynı özelliğin kaç ayrı kodla ve hangi platformlarda yazıldığı sorulur.
Paylaşımın Kuralı
Paylaşımı etiket değil kural verir. Aşağıdaki çekirdek, bir özelliğin iki platformdaki uygulamasını ve bir örnek listesini alır. Bir platformun uygulaması yoksa paylaşım tektir. İki uygulama ayrı işlev nesneleriyse ikizdir. Aynı işlevse ve hiçbir örnekte iki platformun sonucu ayrışmıyorsa ortak, ayrışıyorsa dallıdır.
// 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}`); } }
PLATFORMS platform listesidir; Sharing sınıfı bir özelliğin etiketini, uygulamalarını ve örneklerini alır. code özelliği kaç ayrı işlev nesnesi bulunduğunu, differ özelliği sonucun kaç örnekte platforma göre ayrıştığını tutar. countSharing dört paylaşımı sabit sırayla sayar ve sıfır olanı da basar. Kural bu işi yapan tek yerdir: paylaşım hiçbir yerde elle atanmaz.
Kural iki şeyi görmez. Birincisi bedeldir: üç satırlık bir ikiz ile üç yüz satırlık bir ikiz aynı sayılır. İkincisi verilmeyen örnektir: kural yalnız elindeki örneklerde görüneni görür. Bedeli ve örnek seçimini ders düzyazıyla söyler, kural söylemez.
Derslerdeki ölçüm şöyle kurulur. Bir özelliğin iki platformdaki uygulaması bir işlev tablosu olarak yazılır: ios anahtarının altında bir işlev, android anahtarının altında bir işlev. Tablo gerçek bir derleyiciyi ya da platformu çalıştırmaz.
YA1. Model, bu paylaşımın kuralını kurar; model çapraz platform çerçevesinin kendisi değildir. Platformda bir özelliğin kodu bir dosyada, bir derleme hedefinde ya da bir modülde durur. Modelde ise kodun kendisi bir işlevdir ve iki platformda “aynı kod” demek, tabloda aynı işlev nesnesini göstermek demektir.
Dört Özellik, Dört Paylaşım
Bir uygulamanın dört özelliğini ele alalım. Fiyatı biçimleyen işlev, başlığı kısaltan işlev, izin isteği ve geri düğmesi. İlkinde iki platform aynı işlevi çalıştırır ve işlev platforma bakmaz. İkincisinde aynı işlev çalışır ama kısaltma sınırı platforma göre değişir. Üçüncüsünde her platformun kendi izin işlevi var; ikisi aynı metni üretse de iki ayrı işlev yazılmıştır. Dördüncüsünde geri düğmesi yalnız Android’de vardır, iOS tarafında işlev yoktur. Her özellik dört örnekle ölçülür.
// main.mjs import { PLATFORMS, Sharing, countSharing } from "./sharing.mjs"; function formatPrice(cents) { return `${Math.floor(cents / 100)}.${String(cents % 100).padStart(2, "0")}`; } function shortTitle(title, platform) { const limit = platform === "ios" ? 12 : 16; return title.length > limit ? title.slice(0, limit) + "..." : title; } function iosPermission(kind) { return `izin:${kind}`; } function androidPermission(kind) { return `izin:${kind}`; } function handleBack(screen) { return screen === "ana" ? "cik" : "geri"; } const prices = [0, 199, 1250, 99999]; const titles = ["Kahve", "Haftalik plan", "Market listesi", "Yillik abonelik yenileme"]; const kinds = ["bildirim", "kamera", "konum", "rehber"]; const screens = ["ana", "sepet", "odeme", "profil"]; const features = [ new Sharing("fiyat-bicimi", { ios: formatPrice, android: formatPrice }, prices), new Sharing("baslik-kisaltma", { ios: shortTitle, android: shortTitle }, titles), new Sharing("izin-istegi", { ios: iosPermission, android: androidPermission }, kinds), new Sharing("geri-tusu", { android: handleBack }, screens), ]; console.log(`platformlar: ${PLATFORMS.join(", ")}`); features.forEach((f) => f.line()); countSharing(features);
platformlar: ios, android fiyat-bicimi: kod=1 | fark=0/4 -> ortak baslik-kisaltma: kod=1 | fark=3/4 -> dalli izin-istegi: kod=2 | fark=0/4 -> ikiz geri-tusu: kod=1 | eksik=ios -> tek ortak: 1 dalli: 1 ikiz: 1 tek: 1
Dört özellik dört ayrı paylaşım verdi: ortak 1, dallı 1, ikiz 1, tek 1. Bu dağılım kursun bağlayıcı sayısıdır; örnek sayısı 4, platform sayısı 2’dir. Sonraki dersler bu sayıyı yeniden basmaz, ona atıf yapar.
fiyat-bicimi ortaktır. kod=1 iki platformun aynı işlevi çalıştırdığını, fark=0/4 dört fiyatın ikisinde de aynı yazıldığını söyler. baslik-kisaltma dallıdır: kod yine tektir ama shortTitle sınırı platforma göre seçer. “Haftalik plan” on üç karakterdir: iOS’ta on ikinci karakterden sonra kısalır, Android’de kısalmaz. “Market listesi” on dört karakterdir ve aynı biçimde yalnız iOS’ta kısalır. “Yillik abonelik yenileme” yirmi dört karakterdir; iki platformda da kısalır ama farklı yerden. Dört başlığın üçünde sonuç ayrışır. izin-istegi ikizdir: kod=2, iki ayrı işlev demektir. fark=0/4 ise ikisinin şimdilik aynı şeyi söylediğini gösterir. geri-tusu tektir: eksik=ios iOS uygulamasının bulunmadığını söyler ve fark hesaplanamaz.
Gerekçe Nereden Gelir
Çapraz platform kararı çoğu zaman üç gözlemden doğar. Birincisi ekip büyüklüğüdür: iki ayrı kod tabanı, iki ayrı beceri kümesi ve çoğu zaman iki ayrı ekip demektir. İkincisi ürün tutarlılığıdır: aynı kuralın iki platformda ayrı yazılması, kuralın iki platformda farklı sonuç vermesi riskini taşır. Üçüncüsü yayın ritmidir: bir özellik bir platformda çıkıp öteki platformda haftalarca bekleyebilir. Üçü de gerçek gerekçelerdir ve üçü de ölçüdeki aynı yere işaret eder: ikiz ve tek sayısını azaltmak.
Gerekçenin karşı yanı da aynı ölçüden okunur. Dallı bir özellik, kod tek olsa bile iki platformun farkını içinde taşır; o farkı yazan kişinin iki platformu da tanıması gerekir. Tek özellik ise kod tabanı birleşse bile ortaklaşmaz, çünkü ortak kodun çalışacağı yetenek bir platformda bulunmayabilir. Çapraz platform kararı, bu yüzden “iki kodu bire indirmek” diye değil, her özellik için “hangi paylaşıma düşer” sorusuyla verilir. Kursun sonraki dersleri bu soruyu dört yaklaşımın her biri için sorar ve son derste yaklaşım seçimine bağlar.
İki Kod Tabanının Bedeli
İkiz paylaşımın tipik görüntüsü şudur: aynı kural iki dilde iki kez yazılır. Aşağıdaki iki parça fiyat biçimleyicinin ikiz biçimidir. Sonuç aynıdır, kod iki kez yazılmıştır.
// Platform kodu: PriceFormatter
import Foundation
func formatPrice(cents: Int) -> String {
String(format: "%d.%02d", cents / 100, cents % 100)
}
// Platform kodu: PriceFormatter
fun formatPrice(cents: Int): String =
"%d.%02d".format(cents / 100, cents % 100)
Bu iki parça ölçülmez; model, bu paylaşımın kuralını kurar ve platform derleyicisini çalıştırmaz. Yine de bedeli göstermek için yeterlidir. Kuralı değiştiren biri iki dosyaya dokunur, iki dosyayı iki ayrı sınama düzeneğiyle sınar ve iki ayrı sürümde yayımlar. İki kod başlangıçta aynı sonucu verir; biri unutulduğunda ayrışır. Ayrışmış bir ikiz, ekip büyüdükçe bulunması zorlaşan bir kusurdur.
Tek kod tabanının vaadi bu bedeli bir kez ödemektir. Kural bir yerde yazılır, bir yerde sınanır ve iki platforma birlikte gider. Vaadin sınırı da ölçüde görünür: kod tek kalsa bile baslik-kisaltma gibi bir özellik platforma göre dallanır ve dal da bakım ister. Paylaşımı artırmak, özelliğin her örnekte aynı davranmasını sağlamaz.
Aynı Sepet, İki Platform
Sepet toplamı ortak bir kurala iyi bir örnektir. Sepetteki her satır bir birim fiyat ile bir adet taşır, toplam kuruş cinsinden bulunur ve ekrana yazılırken biçimlenir. İşlev platformu hiç okumaz. Aynı bloğa girdisinden bağımsız bir sabit de koyuyoruz: uygulama adı. Sabit değer döndüren işlev meşrudur ama her zaman ortak verir, çünkü hiçbir girdi sonucu değiştiremez. Bu bir güvence değil, kuralın doğal sonucudur.
// main.mjs import { Sharing, countSharing } from "./sharing.mjs"; function cartTotal(lines) { return lines.reduce((sum, [unitCents, quantity]) => sum + unitCents * quantity, 0); } function shopLabel() { return "Market Defteri"; } const carts = [ [[199, 2], [1250, 1]], [[99, 3]], [[0, 5], [500, 1]], [[99999, 1], [1, 1]], ]; const features = [ new Sharing("sepet-toplami", { ios: cartTotal, android: cartTotal }, carts), new Sharing("sabit-etiket", { ios: shopLabel, android: shopLabel }, carts), ]; features.forEach((f) => f.line()); countSharing(features);
sepet-toplami: kod=1 | fark=0/4 -> ortak sabit-etiket: kod=1 | fark=0/4 -> ortak ortak: 2 dalli: 0 ikiz: 0 tek: 0
İki özellik de ortak çıktı, fark ikisinde de sıfır. sepet-toplami ortaktır çünkü işlev yalnız kendi girdisine bakar. sabit-etiket ortaktır çünkü sonucu hiçbir girdiye bağlı değildir. İkisinin ortak çıkması aynı nedenden değildir: ilkinde işlev girdiyi gerçekten işledi ve iki platformda aynı sonucu verdi, ikincisinde işlenecek bir şey yoktu. Bu fark kuralda görünmez, çünkü kural yalnız fark değerine bakar. Okuyucunun işi, bir özelliğin ortak çıkması karşısında “bu özellik ne yaptı” sorusunu sormaktır.
YA2. Sepet satırlarındaki birim fiyatlar kuruş cinsinden tam sayıdır; model ondalık ve para birimi kurallarını bilmez. Platformda bu kurallar yerel ayar ve biçimleyici sınıfları üzerinden gelir; modelde ise toplam yalnız tam sayı toplamıdır.
Sınırlayıcı Ölçüm
Şimdi aynı işlevi iki kez ölçelim. Bir uygulama simgesinin rozet metnini düşünelim: okunmamış sayı, platforma göre farklı bir üst sınırı aşarsa “99+” ya da “999+” biçimine döner. Rozet işlevi platform bilgisini okur ve bir dal taşır. Önce dala hiç dokunmayan üç örnekle ölçülür: sıfır, beş ve kırk iki okunmamış ileti. Sonra aynı işlev dört örnekle ölçülür: listeye yüz elli eklenir.
// main.mjs import { Sharing, countSharing } from "./sharing.mjs"; function badgeText(count, platform) { const limit = platform === "ios" ? 99 : 999; return count > limit ? `${limit}+` : String(count); } const quiet = [0, 5, 42]; const busy = [0, 5, 42, 150]; const features = [ new Sharing("rozet-3-ornek", { ios: badgeText, android: badgeText }, quiet), new Sharing("rozet-4-ornek", { ios: badgeText, android: badgeText }, busy), ]; features.forEach((f) => f.line()); countSharing(features);
rozet-3-ornek: kod=1 | fark=0/3 -> ortak rozet-4-ornek: kod=1 | fark=1/4 -> dalli ortak: 1 dalli: 1 ikiz: 0 tek: 0
İşlev değişmedi; badgeText her iki ölçümde de aynı işlevdir ve kod=1 kalır. Yalnız örnek listesi değişti. İlk üç örnek dalın eşiğinin altında kaldığı için iki platform aynı metni verdi ve paylaşım ortak çıktı. Yüz elli örneği iOS eşiğini aşar, Android eşiğini aşmaz; iOS “99+” üretirken Android “150” üretir ve paylaşım dallıya döndü.
Bu sonucun iki yorumu var ve ikisi de doğrudur. Birincisi, kuralın yalnız verilen örneklerde görüneni gördüğüdür: dal bir örneğe dokunmadıkça ortak görünür. Bir özelliğin ortak olduğunu söylemeden önce dalı tetikleyecek örneğin listede bulunduğundan emin olmak gerekir. İkincisi, çapraz platform gerekçesinin sınırıdır: kodu tek tutmak, dalı ortadan kaldırmaz. Dal kodun içine taşınmıştır, kuralın dışına çıkmamıştır.
YA3. İki eşik, 99 ve 999, modelin girdisidir. Gerçek bir uygulamada rozet sınırını platform ve ürün kararı belirler; derste bu sayılar bir platform kuralı gibi sunulmaz.
Özet
- Bu dersin paylaşımı: ortak. Ders dört paylaşımı tanıtır ve sepet toplamı iki platformda aynı işlevle, platformu okumadan çalışır.
- Çekirdek ölçümde dört özellik dört paylaşım verdi: ortak 1, dallı 1, ikiz 1, tek 1; örnek sayısı 4, platform sayısı 2.
- İkiz, aynı kuralın iki kez yazılmasıdır; sonuçlar aynı olsa bile bakım iki dosyaya ve iki sınamaya dağılır.
- Sabit değer döndüren işlev her zaman ortak çıkar, çünkü hiçbir girdi sonucu değiştirmez.
- Aynı rozet işlevi üç örnekle ortak, dördüncü örnek eklenince dallı çıktı: kural yalnız verilen örneklerde görüneni görür ve bedeli görmez.
Sonraki Adım
Bu derste kod tabanı sayısı ve paylaşım kavramı kuruldu. Çapraz platform yaklaşımları bu kavramı farklı düzeneklerle değiştirir. Sıradaki ders, Web Görünümü Tabanlı Yaklaşım, arayüzü tek bir sayfadan çizen düzeneği ve sayfanın platform kabuğundan aldığı girdinin paylaşımı nasıl değiştirdiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.