Yazılım Mimarileri ve Tasarım Desenleri Üzerine

Angular – NgRx Kütüphanesi İle State Management

Merhaba,

UI tabanlı geliştirilen Single Page Application(SPA) uygulamalarında ziyaretçilere masaüstü yazılımlarına yakın bir dinamizm ile eşlik edilirken, bu avantajın bir yandan da dezavantajı olabilecek olan sayfada tutarsız verilerin olması durumlarıyla sık sık karşılaşılabilmektedir. Bu tutarsız verilerden kastedileni yazının ilerleyen paragraflarında daha da açacak olsak dahi kısaca bahsetmemiz gerekirse eğer; misal olarak uygulama ekranında sepette üç ürün gözüküyorken, metinsel kısımda ise bu sayı sepettekiyle tutarlılık göstermiyor olabilir. Ya da sepete yeni bir ürün eklendiğinde veya çıkarıldığında biryandan metinsel kısmın duruma göre güncellenmesi beklenir. Ama bazen olmayabilir. Olmayabilir, çünkü uygulama geliştirme sürecinde kullanılan pattern’ın bizlere sağlayabildiği kadar güncellemelere özen gösterilse dahi bir yerden sonra uygulama kompleksitesi artarak, bu güncellemeleri yapmak ve yönetmek zorlaşabilir. İşte bu tarz, uygulama üzerinde tutarlılığı ilgilendiren ve bir verinin bütünselliği açısından yönetilebilirliği sağlamak için geliştirilen genel stratejiye State Management denmektedir. Şimdi gelin bu kavram nedir, kökleri nerelere dayanmaktadır ve bizlere çözüm olarak ne gibi yapılar sunmaktadır hep beraber inceleyelim.

Herşeyden önce, State Management’i anlayabilmek için State kavramını anlamak gerekmektedir. Bizler, önceden kaleme almış olduğumuz Finite-State Machine Nedir? başlıklı makalemizde bir program/yazılım için state’in ne manaya geldiğine değinmiştik. İlgili makaleye göz atmanızı önermekle birlikte yine de bu içeriğimizde konuyu aydınlatabilmek için ayrı bir dille izah etmeye çalışacağız.

State Nedir?

Bir uygulama için state, o uygulamanın tüm belleğidir diyebiliriz. Yani, uygulama sürecindeki herhangi bir veri o anki state’i temsil etmektedir.

İşte state bu! Peki State Management nedir? diye sorduğunuzu duyar gibiyim…

State Management Nedir?

Uygulamadaki verilerden(yani state’lerden) herhangi biri değişkenlik gösterdiği taktirde, bu veriyi/state’i kullanan tüm noktalarda bu değişikliğin yansıması gerekmektedir. İşte bu state’lerin(yani verilerin) kullanıldığı farklı noktalar üzerinde anlık değişimlerin yansımasına ise State Management denmektedir.

En yalın haliyle State Management’ında ne olduğunu öğrendikten sonra muhtemelen aklınızdaki Peki hoca, NgRx kütüphanesi nedir? misali sualinizi cevaplandırmaya çalışalım…

NgRx Kütüphanesi Nedir?

NgRx kütüphanesini anlayabilmek için Redux’ı, Redux’ı anlayabilmek için ise Flux Pattern’i anlamamız gerekmektedir. Haliyle, konuyu net kavrayabilmek ve özümseyebilmek için en temelden ele almamız gerekmektedir. Eee hadi o zaman, fazla vakit kaybetmeden, buyrun başlayalım…

İlk etapta konuyu Angular mimarisi bazında ele alarak başlayacağız. Biliyorsunuz ki, tipik bir Angular uygulaması birçok bileşenden meydana gelecek şekilde tasarlanabilmekte ve uygulamadaki bu bileşenlerin her biri, diğer bileşenlerin haberi olmayacak şekilde kendilerine has state’ler barındırabilmektedir. Bu bileşenlerin, bir araya gelerek meydana getirdikleri uygulamada nihai olarak bütünsel anlamda bir uygulama verisi söz konusu olmaktadır. İşte bu durumda, bileşenlerden herhangi birinde oluşacak state değişimi, bütünsel anlamda o state’i kullanan diğer bileşenlere de yansıtılması gerekmektedir. Yani anlayacağınız birden çok bileşen bir araya geldiği zaman, sayfa tutarlılığı açısından bu bileşenlerdeki state’lerin yönetilmesi gerekmektedir.

Esasında, bileşenler arasında state değişiklikleri için gerekli haberleşmeyi parent ve child seviyesinde @Input ve @Output tanımları aracılığıyla gerçekleştirebilmekteyiz. Bu konuya dair gerekli teferruat için Angular’da @Input ve @Output Değişkenler İle Componentler Arası İletişim başlıklı makaleyi okumanız yeterli olacaktır.
Bir bileşendeki değişikliği @Input veya @Output tanımları aracılığıyla diğer bileşene iletmek, yandaki şemada görüldüğü üzere makul sayıdaki bileşenlerin kullanıldığı senaryolar için geçerli olacaktır. Kullanılan bileşenlerin sayısı sağdaki şemada olduğu gibi arttıkça, @Input ve @Output ile state bilgilerinin iletilmesi bildiğiniz kabus haline gelecektir. Misal olarak, ‘Component 3’den ‘Component 6’ya bir veri aktarmamız gerekiyorsa eğer bunu adı geçen yöntemlerle uygulamak, deveye hendek atlattırmakla eşdeğerdir. Nihayetinde bu uygulama bir gayeye hizmet etmek için geliştirilirken, maliyetin büyük çoğunluğu bu yüksek kompleksiteye sahip operasyon için harcanıyor olacaktır.

İşte bu durum klasik bir State Management problemi ortaya koymaktadır.

Bu klasik State Management probleminin daha da tarihsel bir mazisi var mı?

Tabi ki de! Özünde bu tarz State Management problemini ilk olarak Facebook‘un yaşadığına dair söylentiler mevcut. Hatta bir zamanlar Facebook’un chatbox’ında ki verilerle mesaj sayfasındakilerin pek tutarlılık göstermediğini bizzat tecrübe etmişliğim vardır(gerçi şimdiki haline dairde bir fikrim yok) İşte bu durum state management ile ilgilidir. Facebook, aynı verileri kullanacak şekilde zamanla eklenen ekstra bileşenlerin eşliğinde uygulamadaki state management kompleksitesinin arttığını söylemekte ve bunun sebebini kullandığı klasik veri/model yaklaşımına yüklemektedir.

Bu modelde view’ın render edilmesi modeldeki değişiklik üzerine kurgulanmıştır. Halbuki bir view’deki modelde yapılan değişiklik, o modeli kullanan diğer bir view(ler)’e yansımadığı sürece tutarsızlık söz konusu olacaktır.
Burada view’den kasıt component’lerdir.

Haliyle Facebook buradaki two way databinding modeli yerine bir yerden sonra daha gelişmiş bir stratejiyi modellemektedir, Flux Pattern!

Flux Pattern Nedir?

Kaynak : https://krasimir.gitbooks.io/react-in-patterns/content/chapter-08/


Flux Pattern, yukarıdaki şemada görüldüğü üzere view’de olabilecek herhangi bir state değişikliğini ifade eden action isimli talimatı dispatcher’a göndererek, onun aracılığıyla store’lara bildirmektedir.

Peki nedir bu action, dispatcher ve store?

Yukarıdaki döngü işlediği an, state’de değişiklik gerçekleşecek ve artık ilgili state’i kullanan tüm view’lerin haberdar edilmesi gerekecektir. Haliyle bu işlemi de Controller View ismini verdiğimiz mekanizma üstlenecektir.
Controller View, yandaki şema da görüldüğü üzere uygulamadaki tüm view’ler ile haberleşen bir nesnedir. Eğer ki store’da herhangi bir state verisinde bir değişiklik olursa buna göre view’leri render edecektir.

İşte Flux Pattern bu şekilde bir mantıkla uygulanmaktadır. Dikkat ederseniz eğer uygulama yapısı büyüdükçe ve uygulamanın kompleksitesi arttıkça bu pattern’ın uygulanması zorlaşmaktadır. Çünkü birden fazla store’un kullanılması, zamanla uygulama büyüklüğüyle doğru orantılı bir şekilde birbirlerine bağımlı olabilmelerine sebep olmakta ve bunların orkestra edilmesi git gide zorlaşmaktadır.

Bu noktada bu pattern’in daha rahat uygulanmasını sağlayan Redux karşımıza çıkmaktadır.

Redux Nedir?

Angular gibi JavaScript temelli uygulamalarda State Management süreçlerini basitleştirmek için kullanılan pattern’dır. Temel olarak Single source of truth​, State is read-only​ ve Changes are made with pure functions​ olmak üzere üç ilkeye dayanmaktadır. Direkt ilkeleri izah etmemiz gerekirse eğer;

Kaynak : https://blog.mazarin.lk/productive-development-react-redux/

Redux’u daha iyi anlayabilmek için yandaki görsel şemayı incelemenizde fayda görmekteyim.

Dikkat ederseniz eğer Redux tek bir store’dan beslenmekte ve tüm component’lere o store üzerinden veri sağlamaktadır. Redux’un kullanılmadığı durumlarda ise bir arapsaçı misali davranış sergilenmektedir.

Redux’da state, read-only’dir. Değişmez! (Flux pattern’da değişiklik oluyordu!) Redux’da immutability prensibi söz konusudur. State değişecekse eğer mevcut olan kopyalanıp, üzerinde değişiklik gerçekleştirilerek işlem sağlanır.

Peki Redux pattern’ın çalışma mantığı nasıldır?
Redux pattern’ın çalışma mantığını anlayabilmek için aşağıdaki görsel şemayı incelemenizi tavsiye ederim.

Kaynak : https://labs.tadigital.com/index.php/2020/04/20/getting-started-with-redux/

Şemadan görüldüğü üzere, UI’da(yani view’de) herhangi bir state değişikliği söz konusu olduğunda bu değişikliği temsil eden bir action fırlatılmakta ve fırlatılan bu action’ı reducer fonksiyonu ile yakalayarak yapılan değişiklik algılanmakta ve store’da ki mevcut state yerine gerekli güncellemelerin yapıldığı yeni state oluşturularak, store’a gönderilmektedir. Bu işlem neticesinde, store’da yenilenen state verisi ilgili tüm view’ler tarafından güncellenmiş olacaktır.

Konuyu teoride daha da netleştirebilmek için aşağıdaki hareketli görseli inceleyiniz.

Kaynak : https://ichi.pro/tr/redux-icin-crash-course-98889338959570

Evet… NgRx ile ilgili tüm altyapıyı incelediğimize göre artık sadede gelebiliriz. NgRx Nedir? sorusunu cevaplayabiliriz.

NgRx, Redux Pattern’i benimsemiş ve RxJS kütüphanesiyle desteklenmiş olan Angular’a özel State Management çözümleri için geliştirilmiş bir kütüphanedir.

Şimdi, sonlara doğru NgRx ile basit bir örnek üzerinden içeriğimizi zenginleştirip, noktalayalım.

NgRx Kütüphanesi İle Örnek State Management Uygulaması

İcra edeceğimiz örnekte bir ders uygulamasını baz alıyor olacağız. Bu uygulamada dersleri eklediğimiz, listelediğimiz ve ders adedini yayınladığımız üç farklı componentimiz olacaktır. Haliyle ders sayısında herhangi bir değişiklik olduğu taktirde listeleme ve adedi göstermekten sorumlu componentlerin gerekli güncellemeleri yapabilmesi için NgRx ile state management’ı sağlıyor olacağız.

Her şeyden önce uygulamada kullanacağımız kütüphaneleri aşağıdaki npm komutu eşliğinde yükleyerek başlayalım.
npm i jquery bootstrap @ngrx/store
(Angular uygulamalarında NgRx kütüphanesini @ngrx/store paketi sağlamaktadır.)

Ardından uygulamada kullanılacak componentleri oluşturalım.
ng g c components/lessonCreate
ng g c components/lessonRead
ng g c components/lessonCount

Şimdi hafiften kodlamaya girerek başlayalım.

‘app.component.html’ dosyasında uygulamanın genel HTML çatısını aşağıdaki gibi oluşturalım. Tabi bu konuda sizler kendi özgür iradenize göre çalışma sergileyebilirsiniz. Ben deniz, hasbel kader aşağıdaki gibi (kıytırıktan)bir tasarım üzerinden yürüyor olacağım.

<div class="row">
  <div class="col-md-3">Ders Ekle</div>
  <div class="col-md-3">Ders Listesi</div>
  <div class="col-md-3">Ders Adedi</div>
</div>
<div class="row">
  <div class="col-md-3" style="background-color: antiquewhite;">
    <app-lesson-create></app-lesson-create>
  </div>
  <div class="col-md-3" style="background-color: darkgrey">
    <app-lesson-read></app-lesson-read>
  </div>
  <div class="col-md-3" style="background-color: ghostwhite">
    <app-lesson-count></app-lesson-count>
  </div>
</div>

Ardından uygulamada verisel açıdan bir derse karşılık gelecek olan ‘Lesson’ isimli entity’i oluşturalım.

export class Lesson {
    id: number;
    lesson: string;
    explanation: string;
}

Bu noktadan itibaren uygulamamızın temellerini atmış bulunmaktayız. Artık yapılması gereken NgRx enstrümanlarını tek tek inşa etmektir. Hadi buyrun başlayalım.

NgRx’in enstrümanlarını inşa ettiğimize göre artık component’ler de gerekli geliştirmeleri gerçekleştirebiliriz.

İşte bu kadar…

Uygulamayı derleyip, çalıştırdığımızda aşağıdaki ekran görüntüsünde olduğu gibi davranış gösterecektir.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek projeyi indirmek için buraya tıklayınız.

Mobil sürümden çık