Stuart Sierra'nın " Data In Thinking " konusundaki konuşmasını izledim ve yaptığım oyunda bu fikirlerden birini tasarım ilkesi olarak aldım. Aradaki fark Clojure'de çalışıyor ve ben JavaScript'te çalışıyorum. Buradaki dillerimiz arasında bazı büyük farklılıklar görüyorum:
- Clojure deyimsel olarak işlevsel programlama
- Çoğu devlet değişmez
Fikrini "Her Şey Bir Harita" slaytından aldım (11 dakika, 6 saniye ila> 29 dakika arası). Söylediği bazı şeyler:
- Ne zaman 2-3 argüman alan bir işlev görürseniz, onu bir haritaya dönüştürmek ve sadece bir haritayı geçmek için bir dava açabilirsiniz. Bunun bir çok avantajı vardır:
- Argüman sırası hakkında endişelenmenize gerek yok
- Herhangi bir ek bilgi için endişelenmenize gerek yok. Fazladan anahtarlar varsa, bu bizim endişemiz değil. Sadece akarlar, karışmazlar.
- Bir şema tanımlamanız gerekmez
- Bir Nesne'ye geçmenin aksine, hiçbir veri gizleme yoktur. Ancak, veri gizlemenin sorunlara yol açabileceğini ve abartıldığını iddia ediyor:
- Verim
- Uygulama kolaylığı
- Ağ üzerinden veya işlemler arasında iletişim kurar kurmaz, her iki tarafın da veri gösterimi konusunda hemfikir olmanız gerekir. Bu sadece veri üzerinde çalışıyorsanız, atlayabileceğiniz fazladan bir iş.
Benim sorumla en alakalı. Bu işlem 29 dakikadır: "İşlevlerinizi daha iyi hale getirin". İşte kavramı açıklamak için kullandığı kod örneği:
;; Bad (defn complex-process [] (let [a (get-component @global-state) b (subprocess-one a) c (subprocess-two a b) d (subprocess-three a b c)] (reset! global-state d))) ;; Good (defn complex-process [state] (-> state subprocess-one subprocess-two subprocess-three))
Programcıların çoğunluğunun Clojure ile aşina olmadığını anlıyorum, bu yüzden bunu zorunlu olarak yeniden yazacağım:
;; Good def complex-process(State state) state = subprocess-one(state) state = subprocess-two(state) state = subprocess-three(state) return state
İşte avantajlar:
- Test etmek kolay
- Bu fonksiyonlara yalıtımlı olarak bakmak kolaydır
- Bunun bir satırını yorumlamak kolaydır ve tek bir adımı kaldırarak sonucun ne olduğunu görün
- Her alt süreç, duruma daha fazla bilgi ekleyebilir. Alt işlemin birinciyi alt işlem 3'e iletmesi gerekiyorsa, bir anahtar / değer eklemek kadar basit.
- İhtiyacınız olan verileri, geri kaydedebilmeniz için eyalet dışına çıkarmanız için bir kazan yok. Sadece tüm durumu iletin ve alt işlemin ihtiyaç duyduğu şeyi atamasına izin verin.
Şimdi durumuma döndüm: Bu dersi aldım ve oyunuma uyguladım. Yani, üst düzey işlevlerimin neredeyse tümü bir gameState
nesneyi alıyor ve döndürüyor. Bu nesne oyunun tüm verilerini içerir. EG: Bir badGuys listesi, bir menü listesi, zemindeki yağma vb. Güncelleme fonksiyonumun bir örneği:
update(gameState)
...
gameState = handleUnitCollision(gameState)
...
gameState = handleLoot(gameState)
...
Burada sormak istediğim , yalnızca işlevsel bir programlama dilinde pratik olan bir fikri saptıran bir suistimal yarattım mı? JavaScript deyimsel olarak işlevsel değildir (bu şekilde yazılabilir olsa da) ve değişmez veri yapıları yazmak gerçekten zordur. Beni ilgilendiren şeylerden biri, bu alt işlemlerin her birinin saf olduğunu varsayması . Bu varsayımın neden yapılması gerekiyor? İşlevlerimden herhangi birinin saf olması çok nadir (bununla demek istediğim, sık sık değiştirdikleri anlamına gelir gameState
. Bunun dışında başka karmaşık yan etkilere sahip değilim). Değişmez verileriniz yoksa, bu fikirler dağılıyor mu?
Bir gün uyanacağım ve tüm bu tasarımın sahte olduğunu fark edeceğimden ve gerçekten de sadece Büyük Top Çamur Topuz modelini uyguladığım için endişeleniyorum .
Açıkçası, bu kod üzerinde aylardır çalışıyorum ve harikaydı. İddia ettiği tüm avantajları elde ettiğimi hissediyorum. Kodum, benim için mantıklı gelmesi çok kolaydır . Ama ben tek kişilik bir ekibim, bu yüzden bilgi lanetine sahibim.
Güncelleme
Bu kalıpla 6 + ay kodluyorum. Genellikle bu zamana kadar yaptıklarımı unutuyorum ve orası “bunu temiz bir şekilde yazdım mı?”. devreye giriyor. Yapmasaydım, gerçekten mücadele ederdim. Şimdiye kadar hiç mücadele etmiyorum.
Sürdürülebilirliğini doğrulamak için başka bir göz grubunun nasıl gerekli olacağını anlıyorum. Söyleyebileceğim tek şey, her şeyden önce sürdürülebilirliği önemsiyorum. Nerede çalışırsam çalışayım, temiz kod için her zaman en gürültücü olan benim.
Bu kodlama yöntemiyle zaten kişisel olarak kötü bir deneyime sahip olanlara doğrudan cevap vermek istiyorum. O zaman bilmiyordum ama sanırım kod yazmanın iki farklı yolundan bahsediyoruz. Yaptığım yol, diğerlerinin yaşadıklarından daha fazla yapılandırılmış gibi görünüyor. Birisi "Her şey bir haritadır" konusunda kötü bir kişisel deneyime sahip olduğunda, sürdürmenin ne kadar zor olduğu hakkında konuşurlar:
- İşlevin gerektirdiği haritanın yapısını asla bilmezsin
- Herhangi bir fonksiyon girişi asla beklemeyeceğiniz şekilde değiştirebilir. Belirli bir anahtarın haritaya nasıl girdiğini veya neden kaybolduğunu bulmak için kod tabanının her yerine bakmanız gerekir.
Böyle bir deneyime sahip olanlar için, belki de üssü "Her şey N tür haritaların 1 alır." Oldu. Mine, "Her şey 1 tür harita 1 alır" dir. Bu 1 tipin yapısını biliyorsanız, her şeyin yapısını bilirsiniz. Tabii ki, bu yapı genellikle zamanla büyür. Bu yüzden...
Referans uygulamasının aranacağı bir yer var (yani: şema). Bu referans uygulaması, oyunun kullandığı koddur, bu nedenle eski olamaz.
İkinci noktaya gelince, referans uygulamasının dışındaki haritaya anahtar eklemiyorum / kaldırmıyorum, sadece orada olanları değiştiriyorum. Ayrıca geniş bir otomatik testler grubum var.
Bu mimari sonunda kendi ağırlığının altına düşerse, ikinci bir güncelleme ekleyeceğim. Aksi takdirde, her şeyin yolunda gittiğini varsayalım :)