İçeriğe atla

Önce Çıktı mı, Önce Temel mi? Fazlara Bölünmüş Bir E-Ticaret Örneği

· 7 dk okuma · Mimari

Bu sayfada

Çalıştığım birçok firmada aynı gerilimi yaşadım. Yönetici ve müşteri bir an önce çalışan bir şey görmek ister. Tasarımcı önce token'larını ve küçük bileşenlerini kurmak, frontendçi önce mimari temeli atmak ister. İki taraf da kendi açısından haklı. Sorun, bu baskı altında temelin atlanması ve projenin teknik borçla dolup taşması.

Bu yazıda bu baskının nasıl yönetilmesi gerektiğini bir e-ticaret projesi örneği üzerinden anlattım.

İki Taraf da Haklı

Yönetici için çıktı, işin ilerlediğinin tek kanıtı. Ekranda bir şey yoksa ortada iş de yoktur. Yazılımcı için temel, ileride hızlı gidebilmenin tek yolu. Temel yoksa her yeni sayfa bir öncekinden daha yavaş çıkar.

Martin Fowler bunu Design Stamina Hypothesis yazısında anlatıyor: tasarımı atlayan proje başta daha hızlı iş çıkarır. Fowler'a göre tasarıma yapılan yatırımın karşılığı genelde aylar değil, haftalar içinde alınır; bunun bir tahmin olduğunu da kendisi ekliyor.1 Başka bir yazısında da geliştiricilerin kötü kodun kendilerini birkaç hafta içinde belirgin şekilde yavaşlattığını fark ettiğini söylüyor.2 Yani "temel mi, çıktı mı" bir seçim değil. Asıl soru şu: hangi temeli şimdi, hangisini sonra kuracağız?

Tasarımcı da Aynı Baskıyı Yaşıyor

Tasarımcının "önce token'lar, sonra atomlar, moleküller ve organizmalar, en son sayfalar" diye ilerleme isteği çok tanıdık. Ama atomic design'ı ortaya atan Brad Frost, bunun sıralı bir süreç olmadığını açıkça söylüyor: arayüz hem bir bütün hem de parçalar olarak aynı anda düşünülür.3

Dan Mall da bir tasarım sistemine soyut bileşenlerle değil, gerçek bir ürün parçasıyla, yani bir pilot projeyle başlamayı öneriyor.4 Yani "hemen bir sayfa görelim" talebi tasarımcı için de tamamen yanlış değil. Gerçek bir sayfa, hangi bileşenin gerçekten gerektiğini gösterir. Doğrusu, temeli sayfadan ayrı ve soyut kurmak değil, ilk gerçek sayfayla birlikte kurmak.

Bu yazıdaki fikirlerin hepsi tasarıma da uyar: token isimleri tek yönlü bir kapıdır, bir kartın gölgesi ise çift yönlü.

Hangi Kapıdan Geri Dönülür?

Hangi temelin önce kurulacağına karar vermek için Jeff Bezos'un Amazon'un 2015 hissedar mektubunda anlattığı tek yönlü ve çift yönlü kapı ayrımını kullanıyorum: tek yönlü kapıdan geçtikten sonra geri dönmek çok zordur, çift yönlü kapıdan ise beğenmezsen kolayca geri dönersin.5

  • Tek yönlü kapılar: Veri modeli, API sözleşmesi, routing, klasör yapısı, token isimleri. Sonradan değiştirmek bütün projeye dokunmak demek. Bunlar ilk günden doğru kurulur.
  • Çift yönlü kapılar: Bir bileşenin iç yapısı, bir sayfanın düzeni, bir animasyon. Sonradan değiştirmek tek bir dosyaya dokunmak demek. Bunlar hızlı geçilir, gerekirse sonra düzeltilir.

Bezos'un uyarısı da önemli: kararların çoğu çift yönlüdür ve büyüyen kuruluşlar onlara da tek yönlüymüş gibi davranınca yavaşlar.5 Her şeyi baştan kusursuz kurmaya çalışmak, hiç temel kurmamak kadar zarar verir.

Faz 1: Yürüyen İskelet

İlk fazda müşterinin baştan sona alışveriş yapabildiği en ince sistem kurulur. Buna walking skeleton deniyor. Alistair Cockburn'ün tanımıyla, küçük bir işlevi uçtan uca yerine getiren ve ana mimari bileşenleri birbirine bağlayan çok küçük bir uygulama; mimari ve işlevler bunun üzerinde birlikte büyür.6 Yani atılacak bir prototip değil. Bizim örneğimizde her ekranın yalnızca temel hâlini içeren, gerçek temelin üzerinde duran kod.

Bir e-ticaret sitesinde Faz 1'in kapsamı satın alma yolculuğudur:

  1. Giriş yapmak
  2. Ürünleri listelemek
  3. Ürün detayını görmek
  4. Sepete eklemek
  5. Adres eklemek
  6. Kredi kartıyla ödemek
  7. Siparişlerim sayfasında siparişi görmek

Yönetici bu fazın sonunda ekranlara bakıp "çalışıyor" diyebilir. Ekip de temeli atlamadan oraya gelmiş olur.

ViraStack Start ile kurulan e-ticaret ürünler modülü

Ekran Sonra, Veri Modeli Şimdi

Fazlara bölerken yapılan en yaygın hata, bir özelliği bütünüyle ertelemek. Oysa çoğu özelliğin iki parçası var: ekranı ve veri modeli. Ekran sonraya kalabilir, ama veri modeli ilk fazda doğru kurulmazsa ikinci faz baştan yazmaya döner.

ÖzellikFaz 1'de kurulmalıFaz 2'ye kalabilirVeri modeli de ertelenirse
Ürün varyantlarıÜrün ile varyant ayrımı: fiyat ve stok varyantta dururRenk ve hafıza seçici, varyanta göre değişen görsellerSepet, sipariş ve stok hesabı yeniden yazılır
ÖdemeOrtak bir ödeme arayüzü ve kredi kartıMasterpass ve diğer ödeme yöntemleriHer yeni yöntem ödeme akışının tamamına dokunur
SiparişlerSipariş durumları için genişleyebilen bir yapıİade, değişim ve kargo takibi ekranlarıEski siparişler yeni durumlara taşınmak zorunda kalır
FiyatFiyatın tek bir yerde, sunucuda hesaplanmasıKupon, kampanya ve sepette indirimSepet, ödeme ve sipariş özeti farklı tutarlar gösterir
AramaBasit metin aramasıFiltreler, sıralama, otomatik tamamlamaÜrün verisi filtrelenebilir alanlara bölünmek zorunda kalır
TasarımSemantic token'lar ve temel bileşenlerKoyu tema, mikro etkileşimlerKoyu tema için bütün renkler tek tek aranır
YorumlarHiçbir şeyYorumlar ve puanlarSorun yok: mevcut hiçbir şeye dokunmuyor

Tablonun son sütunu, bir özelliğin ne kadar ertelenebileceğini gösteriyor. Yorumlar bütünüyle sonraya kalabilir, çünkü sonradan eklendiğinde sadece yeni bir bölüm açılır. Varyantların ise ekranı ertelenebilir, ama veri modeli ertelenmemeli.

Ödeme Örneği

İlk fazda yalnızca kredi kartıyla ödeme, Masterpass gibi yöntemler ise ikinci fazda olabilir. Bir ödeme yöntemini sonraya bırakırken ilk fazda yapılması gereken tek şey, ödemeyi tek bir yönteme bağlamamak:

payment.types.ts
type PaymentMethod = "card" | "masterpass"

type PaymentRequest = {
  orderId: string
  method: PaymentMethod
  // En küçük birimde (kuruş) tam sayı: ondalıklı sayılar para hesabında yuvarlama hatası yapar.
  amountInCents: number
}

Faz 1'de yalnızca card çalışır. Faz 2'de Masterpass geldiğinde ödeme sayfası, sipariş kaydı ve sipariş özeti değişmez; sadece yeni bir yöntem eklenir. Bu, ilk fazda küçük bir karar, ama ikinci fazda bütün ödeme akışını yeniden yazmaktan kurtarır.

Teknik Borcu Görünür Tutmak

Hızlı geçilen her yerde bilerek borç alınır. Martin Fowler buna bilinçli ve tedbirli borç diyor: ekip borç aldığını bilir ve erken yayının kazancının, borcu sonradan ödemenin maliyetinden büyük olup olmadığını tartar.7 Bence borcun tedbirli kalması için iki kural yeterli:

  • Her borç bir kayıttır. Borç iş takip aracına yazılır, koddaki not da o kayda link verir. Linksiz bir TODO, zamanla kimsenin okumadığı bir yoruma dönüşür.
  • Not, nedenini söyler. "Düzelt" değil, neyin neden eksik bırakıldığını yazar.

Örneğin varyant seçici ikinci faza bırakılırken galeri bileşenine şöyle bir not düşülebilir:

ProductGallery.tsx
// TODO(SHOP-142): Görseller şimdilik ürün seviyesinde. Varyant seçici gelince
// görseller seçili varyanttan okunacak.

Faz 2: Yayına Hazır

İkinci fazda tablodaki eksikler tamamlanır: varyant seçici, Masterpass, iade ve değişim, yorumlar, filtreler. Veri modeli ilk fazda doğru kurulduysa bu faz, ekranları mevcut yapının üzerine eklemekten ibarettir. Proje bu fazın sonunda yayına hazır hâle gelir.

Borç İçin Ayrı Bir Faz Açmamak

Teknik borcu kapatmak için projenin sonuna üçüncü bir faz koymak cazip gelir. Ama benim deneyimimde ayrı bir borç fazı pek çalışmıyor; teslim tarihi yaklaşınca ilk iptal edilen iş o oluyor.

Bunun yerine borç her faza yayılmalı: her sprintte, her fırsatta, her beklemede biraz borç eritilmeli. Bunun için iki alışkanlık yeterli:

  • Her sprintte işin küçük bir payını borca ayırmak.
  • Dokunulan her dosyayı biraz daha temiz bırakmak.

Böylece proje bittiğinde önünüzde büyük bir borç yığını olmaz, çünkü borç birikmeden küçük küçük ödenmiştir.

Faz 1 Başlamadan Önce Kontrol Listesi

Yeni bir projeye başlarken şu soruların cevabı ilk günden belli olmalı. Hepsi tek yönlü kapı:

  • Ana varlıklar ve aralarındaki ilişkiler belli mi? Örneğin ürün ile varyant, sipariş ile sipariş satırı.
  • Fiyat, stok ve toplam tutar tek bir yerde mi hesaplanıyor?
  • Para tam sayı olarak, en küçük birim cinsinden mi tutuluyor?
  • Durumu olan her şey (sipariş, ödeme, iade) yeni durumlar eklenebilecek şekilde mi kurulu?
  • API sözleşmesi ve hata biçimi tek ve tutarlı mı?
  • URL yapısı ve routing kalıcı olacak şekilde mi tasarlandı?
  • Klasör yapısı ve özellik sınırları belli mi?
  • Token'lar görünüşe göre değil, role göre mi isimlendirildi?
  • Birden fazla dil ya da para birimi ihtimali varsa altyapısı hazır mı?

Bu listenin dışındaki her şey çift yönlü kapıdır: hızlı geç, borcu kaydet, sonra düzelt.

Özet

  • Çıktı ile temel arasında seçim yapılmaz; hangi temelin önce kurulacağına karar verilir.
  • Temel, gerçek bir sayfadan ayrı değil, onunla birlikte kurulur. Bu tasarımcı için de geçerli.
  • Tek yönlü kapılar ilk günden doğru kurulur; çift yönlü kapılarda hızlı geçilir.
  • İlk faz, uçtan uca çalışan en ince sistemdir: walking skeleton.
  • Bir özelliğin ekranı sonraya kalabilir, veri modeli kalmamalı.
  • Her borç bir kayda bağlanır ve nedenini söyler.
  • Borç ayrı bir fazda değil, her sprintte küçük küçük ödenir.

Kaynaklar

  1. Martin Fowler: Design Stamina Hypothesis

  2. Martin Fowler: Is High Quality Software Worth the Cost?

  3. Brad Frost: Atomic Design, Chapter 2

  4. Dan Mall: Design Systems: Pilots & Scorecards

  5. Jeff Bezos: Amazon 2015 Letter to Shareholders

  6. C2 Wiki: Walking Skeleton (Alistair Cockburn'ün tanımı)

  7. Martin Fowler: Technical Debt Quadrant