﻿
{"id":21539,"date":"2021-04-27T20:40:04","date_gmt":"2021-04-27T20:40:04","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=21539"},"modified":"2021-04-30T13:59:45","modified_gmt":"2021-04-30T13:59:45","slug":"basit-bir-event-sourcing-uygulamasi-gelistirelim","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/basit-bir-event-sourcing-uygulamasi-gelistirelim\/","title":{"rendered":"Basit Bir Event Sourcing Uygulamas\u0131 Geli\u015ftirelim"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Bu i\u00e7eri\u011fimizde bir \u00f6nceki kaleme ald\u0131\u011f\u0131m\u0131z <a href=\"https:\/\/www.gencayyildiz.com\/blog\/event-sourcing-nedir-haydi-gelin-hep-beraber-inceleyelim\/\" rel=\"noopener\" target=\"_blank\">Event Sourcing Nedir? Haydi Gelin Hep Beraber \u0130nceleyelim<\/a> ba\u015fl\u0131kl\u0131 makalemize basit bir somut \u00f6rnek te\u015fkil edecek \u015fekilde \u00e7al\u0131\u015fma ger\u00e7ekle\u015ftirece\u011fiz. Amac\u0131m\u0131z Event Sourcing&#8217;in pratikte ucundan k\u0131y\u0131s\u0131ndan tad\u0131na bakmak ve konuya dair sonradan kaleme alaca\u011f\u0131m\u0131z Event Store gibi bir tool&#8217;un \u015fimdiden k\u0131ymetini anlamak \ud83d\ude42 Evet&#8230; O halde haz\u0131rsan\u0131z ba\u015flayal\u0131m&#8230;<\/p>\n<h3>Kurgu<\/h3>\n<p>\u0130lk olarak yapaca\u011f\u0131m\u0131z \u00e7al\u0131\u015fmaya dair genel kurgudan bahsetmek istiyorum. \u00d6rneklendirmemiz bir console uygulamas\u0131 \u00fczerinde var olan &#8216;Person&#8217; nesnesine dair &#8216;Command&#8217; ve &#8216;Query&#8217;lerin ayr\u0131m\u0131 \u00fczerinden seyredecektir. Haliyle buradan anla\u015f\u0131l\u0131yor ki, temel <a href=\"https:\/\/www.gencayyildiz.com\/blog\/cqrs-pattern-nedir-mediatr-kutuphanesi-ile-nasil-uygulanir\/\" rel=\"noopener\" target=\"_blank\">CQRS pattern<\/a> e\u015fli\u011finde basit bir Event Sourcing yakla\u015f\u0131m\u0131 sergileyece\u011fiz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    record Person\r\n    {\r\n        public int Id { get; init; }\r\n        public string Name { get; private set; }\r\n        public int Age { get; private set; }\r\n\r\n        public Person(int id, string name, int age)\r\n        {\r\n            Id = id;\r\n            Name = name;\r\n            Age = age;\r\n        }\r\n\r\n        public void ChangeName(string name)\r\n        =&gt; Name = name;\r\n        public void ChangeAge(int age)\r\n        =&gt; Age = age;\r\n    }\r\n\r\n    class PersonSource\r\n    {\r\n        public static List&lt;Person&gt; PersonList { get; } = new()\r\n        {\r\n            new(1, &quot;Gen\u00e7ay&quot;, 28),\r\n            new(2, &quot;Hilmi&quot;, 30),\r\n            new(3, &quot;Co\u015fgun&quot;, 42),\r\n            new(4, &quot;R\u0131fk\u0131&quot;, 32)\r\n        };\r\n    }\r\n<\/pre>\n<h4>CQRS Temelinin Olu\u015fturulmas\u0131<\/h4>\n<p>\u00d6ncelikle CQRS temelini atarak uygulamay\u0131 in\u015fa etmeye ba\u015flayabiliriz.<br \/>\n<strong>Query<\/strong><br \/>\nRequest nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetPersonQueryRequest\r\n    {\r\n        public int Id { get; set; }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetAllPersonQueryRequest\r\n    {\r\n\r\n    }\r\n<\/pre>\n<p>Response nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetPersonQueryResponse\r\n    {\r\n        public Person Person;\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetAllPersonQueryResponse\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n        public int Age { get; set; }\r\n    }\r\n<\/pre>\n<p>Handler nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetPersonQueryHandler\r\n    {\r\n        public GetPersonQueryResponse GetPerson(GetPersonQueryRequest request)\r\n        {\r\n            Person person = PersonSource.PersonList.FirstOrDefault(p =&gt; p.Id == request.Id);\r\n            return new GetPersonQueryResponse\r\n            {\r\n                Person = person\r\n            };\r\n        }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class GetAllPersonQueryHandler\r\n    {\r\n        public List&lt;GetAllPersonQueryResponse&gt; GetAll(GetAllPersonQueryRequest request)\r\n        {\r\n            return PersonSource.PersonList.Select(person =&gt; new GetAllPersonQueryResponse\r\n            {\r\n                Id = person.Id,\r\n                Age = person.Age,\r\n                Name = person.Name\r\n            }).ToList();\r\n        }\r\n    }\r\n<\/pre>\n<p><strong>Command<\/strong><br \/>\nRequest nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class ChangeNamePersonCommandRequest\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class ChangeAgePersonCommandRequest\r\n    {\r\n        public int Id { get; set; }\r\n        public string Age { get; set; }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class CreatePersonCommandRequest\r\n    {\r\n        public int Id { get; set; }\r\n        public string Name { get; set; }\r\n        public int Age { get; set; }\r\n    }\r\n<\/pre>\n<p>Response nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class ChangeNamePersonCommandResponse\r\n    {\r\n        public bool Register = true;\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class ChangeAgePersonCommandResponse\r\n    {\r\n        public bool Register = true;\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class CreatePersonCommandResponse\r\n    {\r\n        public Person Person { get; set; }\r\n    }\r\n<\/pre>\n<p>Handler nesneleri:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class ChangeNamePersonCommandHandler\r\n    {\r\n        public ChangeNamePersonCommandResponse ChangeName(ChangeNamePersonCommandRequest request)\r\n        {\r\n            Person person = PersonSource.PersonList.FirstOrDefault(p =&gt; p.Id == request.Id);\r\n            person.ChangeName(request.Name);\r\n            return new ChangeNamePersonCommandResponse\r\n            {\r\n                Register = true\r\n            };\r\n        }\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        public ChangeAgePersonCommandResponse ChangeAge(ChangeAgePersonCommandRequest request)\r\n        {\r\n            Person person = PersonSource.PersonList.FirstOrDefault(p =&gt; p.Id == request.Id);\r\n            person.ChangeAge(request.Age);\r\n            return new ChangeAgePersonCommandResponse\r\n            {\r\n                Register = true\r\n            };\r\n        }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class CreatePersonCommandHandler\r\n    {\r\n        public CreatePersonCommandResponse CreatePerson(CreatePersonCommandRequest request)\r\n        {\r\n            PersonSource.PersonList.Add(new Person(request.Id, request.Name, request.Age));\r\n            return new CreatePersonCommandResponse\r\n            {\r\n                Person = PersonSource.PersonList.Last()\r\n            };\r\n        }\r\n    }\r\n<\/pre>\n<p>Evet&#8230; G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere CQRS pattern&#8217;a uygun bir \u015fekilde gelecek istekleri ay\u0131rm\u0131\u015f olduk. Bundan sonra herhangi bir &#8216;Person&#8217; nesnesine yap\u0131lan &#8216;Command&#8217; isteklerini event olarak tutabilmemiz i\u00e7in \u00f6ncelikle &#8216;Event&#8217; tasar\u0131mlar\u0131nda bulunmamam\u0131z gerekmektedir.<\/p>\n<h4>Event Tasar\u0131mlar\u0131n\u0131 Ger\u00e7ekle\u015ftirmek<\/h4>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    interface IEvent\r\n    {\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class NameChangedEvent : IEvent\r\n    {\r\n        public Person Person { get; set; }\r\n        public string oldName, newName;\r\n        public NameChangedEvent(Person person, string oldName, string newName)\r\n        {\r\n            Person = person;\r\n            this.oldName = oldName;\r\n            this.newName = newName;\r\n        }\r\n        public override string ToString()\r\n        =&gt; $&quot;Id de\u011feri {Person.Id} olan personelin ad\u0131 de\u011fi\u015ftirilmi\u015ftir.\\nEski ad\u0131 : {oldName}\\nYeni ad\u0131 : {newName}&quot;;\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer bir &#8216;Person&#8217; nesnesinin &#8216;Name&#8217; de\u011ferinin de\u011fi\u015fti\u011fini ifade eden &#8216;NameChangedEvent&#8217; isminde bir s\u0131n\u0131f tasarlanm\u0131\u015ft\u0131r. Ayn\u0131 \u015fekilde &#8216;Age&#8217; de\u011ferinin de\u011fi\u015fti\u011fini ve yeni bir &#8216;Person&#8217; eklendi\u011fini ifade eden &#8216;AgeChangedEvent&#8217; ve &#8216;PersonCreatedEvent&#8217; isimli event s\u0131n\u0131flar\u0131 da a\u015fa\u011f\u0131dad\u0131r.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class AgeChangedEvent : IEvent\r\n    {\r\n        public Person Person { get; set; }\r\n        public int oldAge, newAge;\r\n\r\n        public AgeChangedEvent(Person person, int oldAge, int newAge)\r\n        {\r\n            Person = person;\r\n            this.oldAge = oldAge;\r\n            this.newAge = newAge;\r\n        }\r\n        public override string ToString()\r\n            =&gt; $&quot;Id de\u011feri {Person.Id} olan personelin ya\u015f\u0131 de\u011fi\u015ftirilmi\u015ftir.\\nEski ya\u015f : {oldAge}\\nYeni ya\u015f : {oldAge}&quot;;\r\n    }\r\n<\/pre>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class PersonCreatedEvent : IEvent\r\n    {\r\n        public Person Person { get; set; }\r\n\r\n        public PersonCreatedEvent(Person person)\r\n        {\r\n            Person = person;\r\n        }\r\n\r\n        public override string ToString()\r\n        =&gt; $&quot;Yeni personel {Person.Id} id de\u011ferinde eklenmi\u015ftir.&quot;;\r\n    }\r\n<\/pre>\n<h4>Event Broker Tasar\u0131m\u0131n\u0131 Ger\u00e7ekle\u015ftirmek<\/h4>\n<p>Ve son olarak &#8216;Person&#8217; nesnesi \u00fczerinde yarat\u0131lacak olan t\u00fcm event&#8217;leri toplayacak olan ve gerekli aksiyonlar\u0131 alacak olan &#8216;Event Broker&#8217; nesnesini olu\u015fturmam\u0131z gerekmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class EventBroker\r\n    {\r\n        \/\/Olu\u015fan event'leri depolayaca\u011f\u0131m\u0131z koleksiyon.\r\n        public List&lt;IEvent&gt; allEvents = new();\r\n        \/\/Uygulamada gelen Command isteklerinde devreye girecek event tan\u0131mlan\u0131yor.\r\n        public event EventHandler&lt;object&gt; Commands;\r\n        \/\/Uygulamada gelen Query isteklerinde devreye girecek event tan\u0131mlan\u0131yor.\r\n        public event EventHandler&lt;object&gt; Queries;\r\n        public EventBroker()\r\n        {\r\n            \/\/'Commands' isimli 'EventHandler'a a\u015fa\u011f\u0131daki metot tan\u0131mlan\u0131yor.\r\n            this.Commands += (sender, command) =&gt;\r\n            {\r\n                \/\/E\u011fer gelen Command 'ChangeAgePersonCommandRequest' t\u00fcr\u00fcndense\r\n                if (command is ChangeAgePersonCommandRequest req1)\r\n                {\r\n                    ChangeAgePersonCommandHandler handler = new ChangeAgePersonCommandHandler();\r\n                    ChangeAgePersonCommandResponse response = handler.ChangeAge(req1);\r\n                    \/\/\u0130lgili iste\u011fe uygun event olan 'AgeChangedEvent' nesnesi event deposuna at\u0131l\u0131yor.\r\n                    this.allEvents.Add(new AgeChangedEvent(response.Person, response.OldAge, req1.Age));\r\n                }\r\n                \/\/E\u011fer gelen Command 'ChangeNamePersonCommandRequest' t\u00fcr\u00fcndense\r\n                else if (command is ChangeNamePersonCommandRequest req2)\r\n                {\r\n                    ChangeNamePersonCommandHandler handler = new ChangeNamePersonCommandHandler();\r\n                    ChangeNamePersonCommandResponse response = handler.ChangeName(req2);\r\n                    \/\/\u0130lgili iste\u011fe uygun event olan 'NameChangedEvent' nesnesi event deposuna at\u0131l\u0131yor.\r\n                    this.allEvents.Add(new NameChangedEvent(response.Person, response.OldName, req2.Name));\r\n                }\r\n                \/\/E\u011fer gelen Command 'CreatePersonCommandRequest' t\u00fcr\u00fcndense\r\n                else if (command is CreatePersonCommandRequest req3)\r\n                {\r\n                    CreatePersonCommandHandler handler = new CreatePersonCommandHandler();\r\n                    CreatePersonCommandResponse response = handler.CreatePerson(req3);\r\n                    \/\/\u0130lgili iste\u011fe uygun event olan 'PersonCreatedEvent' nesnesi event deposuna at\u0131l\u0131yor.\r\n                    this.allEvents.Add(new PersonCreatedEvent(response.Person));\r\n                }\r\n            };\r\n            \/\/'Queries' isimli 'EventHandler'a a\u015fa\u011f\u0131daki metot tan\u0131mlan\u0131yor.\r\n            this.Queries += (sender, query) =&gt;\r\n            {\r\n                \/\/E\u011fer gelen Query 'GetPersonQueryRequest' t\u00fcr\u00fcndense\r\n                if (query is GetPersonQueryRequest req1)\r\n                {\r\n                    GetPersonQueryHandler handler = new GetPersonQueryHandler();\r\n                    GetPersonQueryResponse response = handler.GetPerson(req1);\r\n                    Console.WriteLine($&quot;Id\\tName\\tAge&quot;);\r\n                    Console.WriteLine($&quot;{response.Person.Id}\\t{response.Person.Name}\\t{response.Person.Age}\\n***********&quot;);\r\n                }\r\n                \/\/E\u011fer gelen Query 'GetAllPersonQueryRequest' t\u00fcr\u00fcndense\r\n                else if (query is GetAllPersonQueryRequest req2)\r\n                {\r\n                    GetAllPersonQueryHandler handler = new GetAllPersonQueryHandler();\r\n                    List&lt;GetAllPersonQueryResponse&gt; response = handler.GetAll(req2);\r\n                    Console.WriteLine($&quot;Id\\tName\\tAge&quot;);\r\n                    response.ForEach(person =&gt; Console.WriteLine($&quot;{person.Id}\\t{person.Name}\\t{person.Age}&quot;));\r\n                    Console.WriteLine(&quot;***********&quot;);\r\n                }\r\n            };\r\n        }\r\n        \/\/Client'\u0131n 'Command' g\u00f6nderebilmesi i\u00e7in kullanaca\u011f\u0131 metot.\r\n        public void Command(object command)\r\n            =&gt; Commands(this, command);\r\n        \/\/Client'\u0131n 'Query' g\u00f6nderebilmesi i\u00e7in kullanaca\u011f\u0131 metot.\r\n        public void Query(object query)\r\n            =&gt; Queries(this, query);\r\n        \/\/T\u00fcm event'i yazd\u0131rabilmek\/okuyabilmek i\u00e7in kullan\u0131lacak metot.\r\n        public void WriteAllEvent()\r\n            =&gt; allEvents.ForEach(@event =&gt; Console.WriteLine($&quot;{@event.ToString()}\\n***********&quot;));\r\n    }\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz temel d\u00fczeyde bir &#8216;Event Broker&#8217; nesnesinde olmas\u0131 gereken t\u00fcm aksiyonlar tasarlanm\u0131\u015ft\u0131r. Ad\u0131m ad\u0131m kod sat\u0131rlar\u0131nda gerekli a\u00e7\u0131klamalar\u0131 yapt\u0131\u011f\u0131m i\u00e7in burada tekrardan detayland\u0131rmaya girmek istemesem de genel anlamda bir izahatte bulunman\u0131n faydas\u0131 olaca\u011f\u0131 kanaatindeyim: Dikkat ederseniz uygulamadaki t\u00fcm event&#8217;ler, yap\u0131lan &#8216;Command&#8217; ve &#8216;Query&#8217; isteklerine istinaden gerekli olaylar e\u015fli\u011finde, iste\u011fin t\u00fcr\u00fcne g\u00f6re ayr\u0131\u015ft\u0131rma ger\u00e7ekle\u015ftirildikten sonra &#8216;event&#8217; olarak kay\u0131t alt\u0131na al\u0131nmaktad\u0131r. Ard\u0131ndan bu event&#8217;ler istek do\u011frultusunda tekrar listelenebilmekte ve hatta eldeki verinin herhangi bir T zaman\u0131ndaki halini elde edebilecek vaziyette geli\u015ftirilmeye meyletmektedir.<\/p>\n<p>Dolay\u0131s\u0131yla \u015fu a\u015famadan sonra art\u0131k tek yap\u0131lmas\u0131 gereken client&#8217;\u0131 tasarlamak ve test ama\u00e7l\u0131 bir ka\u00e7 &#8216;Command&#8217; yahut &#8216;Query&#8217; isteklerini g\u00f6ndermektir.<\/p>\n<h4>Client<\/h4>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    class Program\r\n    {\r\n        static void Main(string&#x5B;] args)\r\n        {\r\n            EventBroker eventBroker = new EventBroker();\r\n            eventBroker.Command(new CreatePersonCommandRequest { Id = 5, Age = 21, Name = &quot;Muiddin&quot; });\r\n            eventBroker.Command(new CreatePersonCommandRequest { Id = 6, Age = 44, Name = &quot;Fadi\u015f&quot; });\r\n            eventBroker.Command(new ChangeAgePersonCommandRequest { Id = 2, Age = 55 });\r\n            eventBroker.Command(new ChangeAgePersonCommandRequest { Id = 2, Age = 66 });\r\n            eventBroker.Command(new ChangeNamePersonCommandRequest { Id = 3, Name = &quot;Serdar&quot; });\r\n            eventBroker.WriteAllEvent();\r\n            eventBroker.Query(new GetAllPersonQueryRequest());\r\n            eventBroker.Query(new GetPersonQueryRequest() { Id = 3 });\r\n        }\r\n    }\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere client &#8216;<em>CreatePersonCommandRequest<\/em>&#8216;, &#8216;<em>CreatePersonCommandRequest<\/em>&#8216;, &#8216;<em>ChangeAgePersonCommandRequest<\/em>&#8216;, &#8216;<em>ChangeAgePersonCommandRequest<\/em>&#8216; ve &#8216;<em>ChangeNamePersonCommandRequest<\/em>&#8216; olmak \u00fczere be\u015f adet Command iste\u011finde bulunmakta ve akabinde &#8216;<em>GetAllPersonQueryRequest<\/em>&#8216; ve &#8216;<em>GetPersonQueryRequest<\/em>&#8216; olmak \u00fczere iki Query iste\u011fiyle verileri okumak istemektedir. <strong><em>11.<\/em><\/strong> sat\u0131rda ise &#8216;WriteAllEvent&#8217; fonksiyonu ile o ana kadar olu\u015fan t\u00fcm event&#8217;leri listelemektedir. Sonu\u00e7 olarak a\u015fa\u011f\u0131daki gibi bir \u00e7\u0131kt\u0131yla kar\u015f\u0131la\u015f\u0131lmaktad\u0131r.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Basit-Bir-Event-Sourcing-Uygulamasi-Gelistirelim.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Basit-Bir-Event-Sourcing-Uygulamasi-Gelistirelim.png\" alt=\"Basit Bir Event Sourcing Uygulamas\u0131 Geli\u015ftirelim\" width=\"410\" height=\"423\" class=\"aligncenter size-full wp-image-21566\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Basit-Bir-Event-Sourcing-Uygulamasi-Gelistirelim.png 410w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/Basit-Bir-Event-Sourcing-Uygulamasi-Gelistirelim-291x300.png 291w\" sizes=\"auto, (max-width: 410px) 100vw, 410px\" \/><\/a><\/p>\n<p>Evet&#8230; Bu sat\u0131rlara geldiysek e\u011fer art\u0131k hasbel kader bir Event Sourcing operasyonunun nas\u0131l ceyran etti\u011fini anlam\u0131\u015f, hi\u00e7 yoktan tad\u0131na bakm\u0131\u015f bulunmaktay\u0131z. Ve umuyorum ki, yo\u011fun uygulamalarda buradaki gibi event&#8217;leri in-memory&#8217;de depolaman\u0131n maliyetinin a\u011f\u0131rl\u0131\u011f\u0131n\u0131 ve y\u00f6netilebilirli\u011finin g\u00fc\u00e7l\u00fc\u011f\u00fcn\u00fc g\u00f6rd\u00fc\u011f\u00fcn\u00fcz kanaatindeyim. Haliyle event&#8217;leri g\u00fc\u00e7l\u00fc bir \u015fekilde depolayabilmenin ve y\u00f6netebilmenin k\u0131ymetinin \u00f6nemine binaen sonraki yaz\u0131mda Event Sourcing i\u00e7in olduk\u00e7a kullan\u0131\u015fl\u0131 bir tools olan <a href=\"https:\/\/www.eventstore.com\/\" rel=\"noopener\" target=\"_blank\">Event Store<\/a>&#8216;la sizleri tan\u0131\u015ft\u0131rmak istiyorum.<\/p>\n<p>O halde sizler bu makaleyi okuyup sindirene kadar ben de m\u00fcjdesini verdi\u011fim di\u011fer makaleyi klavyeye almaya ba\u015flasam iyi olacak \ud83d\ude42<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek projeyi indirmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/04\/EventSourcingExample.zip\" rel=\"noopener\" target=\"_blank\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Bu i\u00e7eri\u011fimizde bir \u00f6nceki kaleme ald\u0131\u011f\u0131m\u0131z Event Sourcing Nedir? Haydi Gelin Hep Beraber \u0130nceleyelim ba\u015fl\u0131kl\u0131 makalemize basit bir somut \u00f6rnek te\u015fkil edecek \u015fekilde \u00e7al\u0131\u015fma ger\u00e7ekle\u015ftirece\u011fiz. Amac\u0131m\u0131z Event Sourcing&#8217;in pratikte ucundan k\u0131y\u0131s\u0131ndan tad\u0131na bakmak&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":21566,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2739,153,3573],"tags":[4229,4217,4228],"class_list":["post-21539","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-core","category-design-pattern","category-microservices","tag-event-broker","tag-event-sourcing","tag-event-sourcing-example"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21539","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=21539"}],"version-history":[{"count":32,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21539\/revisions"}],"predecessor-version":[{"id":21573,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/21539\/revisions\/21573"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/21566"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=21539"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=21539"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=21539"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}