- Repo yenidir. Sürekli olarak güncellenmektedir. Takibe almayı unutmayın. (Star, Watch)
- Sadece soruların olduğu listeye buradan ulaşabilirsiniz.
- Girdiğiniz mülakatlar da karşınıza çıkan soruları eklemek isterseniz pull request gönderebilirsiniz. Merge ediyorum.
- Virtual yapısı, nesne yönelimli programlama (OOP) konseptlerinden biridir ve bir sınıfın üye işlevlerinin, türetilmiş sınıflar tarafından yeniden tanımlanabileceği anlamına gelir. Bu, türetilmiş sınıfların üye işlevlerinin davranışını kontrol etmesine izin verir.
- Partial sınıflar, C# programlama dilindeki bir özelliktir. Bir sınıfı bölümlere ayırmak ve farklı dosyalarda tanımlamak için kullanılırlar. Partial sınıflar, aynı sınıfa ait kodun farklı dosyalarda veya ayrı bölmelerde dağıtılmasına izin verir.
- Bu özellik, büyük ölçekli projelerde sınıfların daha iyi organize edilmesini sağlar ve birden fazla geliştirici aynı sınıf üzerinde çalışırken çakışmaları azaltır. Örneğin, bir sınıfın uygulama mantığını, arayüz tanımlarını veya veritabanı işlemlerini farklı dosyalarda belirli bölümlere ayırabilirsiniz.
- Partial sınıfların kullanımı, sınıfın kodunun karmaşıklığını azaltır ve sınıfın bakımını ve genişletilebilirliğini kolaylaştırır. Ayrıca, otomatik kod üreten araçlar veya tasarım araçları tarafından üretilen kodu manuel olarak genişletebilir ve değiştirebilirsiniz.
- Kısacası, partial sınıflar, bir sınıfın kodunu farklı dosyalarda veya bölmelerde organize etmek ve büyük projelerde sınıfın geliştirilmesini kolaylaştırmak için kullanılan bir C# özelliğidir.
- Static, OOP'de kullanılan bir anahtar sözcüktür ve sınıf üyeleri veya değişkenler tanımlarken kullanılabilir. Bu, sınıfın örneğine bağlı olmayan bir değişken veya fonksiyon olduğunu gösterir ve bu değişken veya fonksiyona sınıfın adıyla erişilebilir.
- nopCommerce, açık kaynaklı bir e-ticaret platformudur ve .NET teknolojileri kullanılarak geliştirilmiştir. Bu proje, birçok dilde ve para biriminde çeviri desteği, esnek ürün yönetimi ve ödeme entegrasyonu gibi özellikler sunar.
- Elasticsearch, açık kaynaklı bir arama ve analiz motorudur ve büyük miktardaki verileri işlemek ve aramak için kullanılır. Elasticsearch, bir ilişkisel veritabanından farklıdır ve verileri JSON belgeleri olarak saklar.
- Redis, açık kaynaklı bir anahtar-değer depolama sistemidir ve en çok performanslı ve ölçeklenebilir uygulamalarda kullanılır. Redis, verileri bellek içinde saklar ve bu nedenle hızlı bir şekilde erişilebilir.
- İlişkisel veritabanları, verileri birbirleriyle ilişkili tablolarda saklar. Bu, SQL dilinin kullanılmasıyla yapılandırılmıştır. NoSQL veritabanları ise yapılandırması daha esnektir ve genellikle yüksek performanslı uygulamalarda kullanılır.
- Bu konular, OOP'nin temel prensipleridir ve yazılım geliştirme sürecinde sık sık kullanılır. Lazy loading, uygulamanın ihtiyacı olduğu anda verileri yükler ve gereksiz yere kaynak tüketimini önler. Encapsulation, sınıfın içindeki verilerin ve işlevlerin korunmasını sağlar ve sınıfın dışındaki etkileşimlerin kısıtlanmasına yardımcı olur. Polymorphism, bir nesnenin farklı şekillerde davranabilmesini sağlar. Inheritance, bir sınıfın başka bir sınıftan türetilmesini ve üye işlevlerinin ve değişkenlerinin miras alınmasını sağlar.
- SOLID, yazılım geliştirme dünyasında sık sık kullanılan bir prensipler kümesidir. SOLID, Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation ve Dependency Inversion olmak üzere beş prensipten oluşur. Bu prensipler, yazılım geliştiricilerinin yazılımın esnekliğini artırmasına ve daha sürdürülebilir bir kod tabanı oluşturmasına yardımcı olur.
- Solid prensipleri, yazılım geliştirme sürecinde kaliteli, sürdürülebilir ve esnek bir kod oluşturmayı hedefleyen bir dizi kurallardır. SOLID, Robert C. Martin tarafından önerilen ve beş temel prensibi içeren bir akronimdir:
- Single Responsibility Principle (Tek Sorumluluk Prensibi): Her sınıf veya modül, yalnızca bir tek sorumluluğa sahip olmalı ve bu sorumluluğu başarılı bir şekilde yerine getirmelidir.
- Open/Closed Principle (Açık/Kapalı Prensibi): Bir yazılım birimi (sınıf, fonksiyon, modül) değişikliklere kapalı (closed) olmalı, ancak yeni işlevsellik eklemek için açık (open) olmalıdır. Yani mevcut kodu değiştirmek yerine, yeni özellikler eklemek için genişletilebilir olmalıdır.
- Liskov Substitution Principle (Liskov Yerine Geçme Prensibi): Bir üst sınıfın nesneleri, onun alt sınıfları tarafından yerine geçebilmelidir. Yani alt sınıflar, üst sınıfın belirlediği davranışları korumalı ve bu davranışları değiştirmeden genişletebilmelidir.
- Interface Segregation Principle (Arayüz Ayrım Prensibi): İstemcilerin kullanmadığı özellikleri içeren geniş arayüzler yerine, daha küçük ve özelleştirilmiş arayüzler kullanılmalıdır. Bir sınıf, sadece ihtiyaç duyduğu metotları içeren arayüzleri uygulamalıdır.
- Dependency Inversion Principle (Bağımlılığı Tersine Çevirme Prensibi): Yüksek seviyeli modüller, düşük seviyeli modüllere doğrudan bağlı olmamalıdır. Bunun yerine, her iki seviyenin de soyutlamalara (abstractions) bağımlı olması gerekmektedir.
- Bu prensipler, yazılımın daha kolay bakım yapılabilir, test edilebilir ve genişletilebilir olmasını sağlar. Aynı zamanda kodun tekrar kullanılabilirliğini artırır ve bağımlılıkları azaltır.
-
Prosedürler ve fonksiyonlar, programlarda tekrar kullanılabilir kod blokları oluşturmak için kullanılan yapısal programlama araçlarıdır. İkisi arasındaki temel fark, geri dönüş değeri olup olmamasıdır. Prosedürler, belirli bir görevi gerçekleştirmek için kullanılan kod bloklarıdır. Geri dönüş değeri yoktur veya değeri yok sayılır. Genellikle verileri işlemek, ekrana çıktı yazdırmak veya başka bir işlemi gerçekleştirmek gibi işlevleri yerine getirmek için kullanılırlar.
-
Fonksiyonlar ise prosedürlerden farklı olarak geri dönüş değeri olan kod bloklarıdır. Fonksiyonlar, belirli bir hesaplama yapar ve sonucu çağıran yere döndürür. Fonksiyonlar, genellikle bir değeri hesaplamak, işlemek ve bu değeri geri döndürmek için kullanılır. Hangisini tercih edeceğiniz, yapmanız gereken işin doğası ve ihtiyaçlarınıza bağlıdır. Eğer bir görevi gerçekleştirmek için geri dönüş değeri gereksizse veya dikkate alınmayacaksa, prosedür kullanabilirsiniz.
-
Örneğin, ekrana bir metin yazdırmak veya verileri sıralamak için bir prosedür kullanabilirsiniz. Ancak, bir hesaplama yapmanız veya bir değeri döndürmeniz gerekiyorsa, fonksiyonları tercih etmek daha uygun olabilir. Örneğin, iki sayının toplamını hesaplamak veya bir liste içindeki en büyük sayıyı bulmak için bir fonksiyon kullanabilirsiniz. Özetlemek gerekirse, prosedürler genellikle görevleri gerçekleştirmek için kullanılırken, fonksiyonlar hesaplamalar yapmak ve sonuçları döndürmek için tercih edilir. Hangisini seçeceğiniz, işin doğasına ve ihtiyaçlarınıza bağlıdır.
- Dependency Injection (DI), yazılım geliştirme sürecinde sık sık kullanılan bir tasarım desenidir. Bu desen, bir nesnenin ihtiyaç duyduğu bağımlılıkları dışarıdan almasına ve sınıfın içinde doğrudan oluşturulmamasına izin verir. Bu, sınıfların daha bağımsız hale gelmesini ve daha kolay test edilebilir hale gelmesini sağlar.
- Dependency Injection, bir yazılım tasarım deseni olarak, bağımlılıkların (dependencies) dışarıdan bir bileşenin içine enjekte edilmesini sağlar. Bu desen, bir bileşenin bağımlılıklarını oluşturmak ve yönetmek yerine, bu bağımlılıkların dışarıdan bir kaynak tarafından sağlanmasını sağlar.
- Bir örnekle açıklamak gerekirse, bir Araba nesnesi oluşturmak istediğimizi düşünelim. Araba'nın bir motor, lastikler, direksiyon vb. gibi birçok bağımlılığı vardır. Geleneksel bir yaklaşımda, Araba nesnesi oluşturulurken bu bağımlılıkların her biri tek tek oluşturulur veya oluşturulması için başka bir bileşen çağrılır.
- Fakat bu yaklaşım, kodun karmaşıklaşmasına ve sıkı bir şekilde bağımlı hale gelmesine neden olabilir. Bu durumda, Dependency Injection kullanarak Araba nesnesini oluşturmak daha uygun olacaktır.
- Dependency Injection kullanarak, Araba bileşenini oluşturmak istediğimizde, Araba'nın bağımlılıkları dışarıdan bir kaynaktan (örneğin bir IOC Container) alınır ve Araba bileşenine enjekte edilir. Bu sayede Araba bileşeni, bağımlılıklarını yönetmek yerine, bunları dışarıdan gelen kaynak tarafından sağlanır.
- Özetle, Dependency Injection, kodun daha modüler ve esnek olmasını sağlar. Bu desen, yazılım bileşenlerinin birbirlerine sıkı bir şekilde bağımlı olmaktan kurtulmasına ve daha kolay test edilebilmesine olanak tanır.
public class Araba {
private Motor motor;
private Tekerlekler tekerlekler;
private Direksiyon direksiyon;
public Araba(Motor motor, Tekerlekler tekerlekler, Direksiyon direksiyon) {
this.motor = motor;
this.tekerlekler = tekerlekler;
this.direksiyon = direksiyon;
}
// Araba'nın diğer metotları...
}
- Abstract ve Interface, OOP'de sık kullanılan kavramlardır. Abstract sınıflar, bir sınıfın soyut bir temel sınıfı olduğunu belirtir ve soyut işlevleri veya değişkenleri içerebilir. Interface'ler ise, bir sınıfın uygulaması gereken belirli işlevleri tanımlar ve sınıflar arasındaki bağımlılıkları azaltmak için kullanılır.
- Docker, yazılım uygulamalarının hızlı bir şekilde dağıtılmasını, yönetilmesini ve çalıştırılmasını sağlayan bir platformdur. Docker, uygulamanın bağımlılıklarını ve konfigürasyonunu içeren sanal ortamlar oluşturur.
- RabbitMQ, açık kaynaklı bir mesajlaşma aracıdır ve uygulamalar arasındaki mesajlaşmayı kolaylaştırır. Bu araç, birçok farklı protokolü destekler ve birçok dilde kullanılabilir.
- Microservice mimarisi, bir uygulamanın farklı işlevlerinin farklı servisler halinde ayrılmasıdır. Bu yaklaşım, uygulamayı daha esnek hale getirir, ölçeklenebilirliği artırır ve hata ayıklama ve bakımı kolaylaştırır. Monolitik mimari ise, tüm uygulamanın tek bir yapıda oluşturulmasıdır. Bu yaklaşım, uygulama geliştirmeyi daha kolay hale getirir, ancak büyük uygulamalarda ölçeklenebilirlik sorunlarına neden olabilir. Microservice yaklaşımı, uygulamanın her bir işlevini ayrı ayrı yönetme ve ölçekleme imkanı sağlar.
- AddScope: Bu metot, bağımlılık enjeksiyonu konteynerine bir servis kaydederken, bu servisin her talep edildiğinde bir kapsam (scope) boyunca aynı örneğini döndürmesini sağlar. Kapsam boyunca aynı örneğin kullanılması, örneğin bir HTTP isteği süresince aynı servis nesnesinin paylaşılmasını sağlar. Bu genellikle, bir istek içinde birden fazla bileşenin aynı verilere veya durumlara erişmesi gerektiği durumlarda kullanılır.
- AddSingleton: Bu metot, bağımlılık enjeksiyonu konteynerine bir servis kaydederken, bu servisin uygulama ömrü boyunca yalnızca bir kez oluşturulup paylaşılmasını sağlar. Herhangi bir talep edildiğinde aynı örneği döndürür. Bu, uygulama boyunca tek bir örnek kullanmak istediğiniz durumlarda faydalıdır. Örneğin, bir konfigürasyon ayarını veya veritabanı bağlantısını paylaşmak için kullanılabilir.
- AddTransient: Bu metot, her talep edildiğinde yeni bir örnek oluşturarak her bir talep için farklı bir örneği döndürmek üzere bir servis kaydeder. Yani her talep edildiğinde bir örnek oluşturulur ve bu örnek sadece bu talep için kullanılır. Bu, hafızada paylaşımlı bir durumu veya veriyi saklamak yerine, her talep edildiğinde taze bir örneğe ihtiyaç duyduğunuz durumlarda kullanışlıdır. Örneğin, geçici bellek kullanıcı oturumlarını veya işlem durumunu depolamak için kullanılabilir.
- Bu üç metot, bağımlılıkların nasıl kaydedileceği ve hangi örneklerin nasıl döndürüleceği konusunda farklı davranışları temsil eder. Uygulamanızın gereksinimlerine göre doğru yöntemi seçmek önemlidir.
- Int32 ve Int64, tamsayı veri tiplerini ifade eder. Farkları, temsil ettikleri tamsayı değerlerinin boyutlarından kaynaklanır.
- Int32, 32 bit (4 byte) uzunluğunda bir tamsayıyı temsil eder. Bu veri tipi, -2,147,483,648 ile 2,147,483,647 arasındaki tamsayı değerlerini alabilir. Negatif ve pozitif değerler için aynı miktarda alan ayrılır.
- Int64 ise 64 bit (8 byte) uzunluğunda bir tamsayıyı temsil eder. Bu veri tipi, -9,223,372,036,854,775,808 ile 9,223,372,036,854,775,807 arasındaki tamsayı değerlerini alabilir. Negatif ve pozitif değerler için aynı miktarda alan ayrılır.
- Bu nedenle, Int32 daha küçük bir değer aralığına ve daha az bellek kullanımına sahiptirken, Int64 daha büyük bir değer aralığına ve daha fazla bellek kullanımına sahiptir. Seçiminiz, temsil etmek istediğiniz değerlerin aralığına bağlı olacaktır.
- DataRow ve DataReader, .NET Framework'teki ADO.NET kütüphanesindeki farklı sınıflardır ve veritabanı işlemleriyle ilgili farklı amaçlar için kullanılırlar.
- DataRow, DataTable nesnesindeki bir veri kaydını temsil eder. DataTable, tablo yapısında verileri depolamak için kullanılan bir sınıftır. DataRow ise DataTable içindeki her bir veri kaydını temsil eder. Bir DataRow nesnesi, tablodaki her bir sütunun değerlerini saklar.
- DataReader ise veritabanı işlemlerinde verileri okumak için kullanılan bir sınıftır. Bir veritabanı sorgusu çalıştırıldığında, DataReader sorgu sonucundaki veri akışını temsil eder ve verileri satır satır okur. DataReader, verileri sorgudan döndürerek, bellekte daha az yer kaplayarak daha hızlı ve verimli bir şekilde çalışır. Verileri tek yönlü (forward-only) olarak okur, yani ileri doğru hareket ederek verilere erişir. DataReader, veritabanı bağlantısı açık olduğu sürece verileri okumaya devam eder.
- Özetle, DataRow verileri tablo yapısında saklamak ve işlemek için kullanılırken, DataReader verileri veritabanından okumak ve işlemek için kullanılır.
- C# dilinde Dictionary ve List, farklı veri yapılarıdır ve farklı amaçlar için kullanılırlar. İkisi arasındaki ana fark, verileri nasıl depoladıkları ve erişim süreleridir.
- Depolama Yapısı:
- List: List, elemanları bir sıra içinde depolar. Her eleman bir indeks numarasıyla erişilebilir ve elemanlar eklenme sırasına göre tutulur.
- Dictionary: Dictionary, bir anahtar-değer çiftleri koleksiyonunu depolar. Her bir anahtar benzersiz olmalıdır ve her anahtarın karşısında bir değer bulunur. Anahtarlar, elemanları hızlı bir şekilde erişmek için kullanılır.
- Erişim Süresi:
- List: List, indeks numarasına dayalı olarak elemanlara erişir. Dolayısıyla, bir elemana erişmek için indeks numarasını bilmek gereklidir. Elemanlara erişim süresi O(1) olarak kabul edilir.
- Dictionary: Dictionary, anahtarlar aracılığıyla elemanlara erişir. Anahtarın değeri bulmak için bir karma işlev kullanılır. Bu karma işlemi sayesinde elemanlara hızlı bir şekilde erişilebilir. Elemanlara erişim süresi de O(1) olarak kabul edilir.
- Sonuç olarak, Dictionary ve List arasında erişim hızı açısından bir fark yoktur, her ikisi de O(1) süresinde elemanlara erişir. Ancak, elemanlara erişmek için kullanılan yöntemler farklıdır. Listeler, indeks numaralarına dayalı olarak elemanlara erişim sağlar, Dictionary'ler ise anahtarlar aracılığıyla elemanlara erişir. Dolayısıyla, kullanmanız gereken veri yapısı, işlevsel gereksinimlerinize ve verilerinizi nasıl organize etmek istediğinize bağlıdır.
- C# dilinde "sealed" (mühürlü) bir sınıf, miras alınmasını engellemek için kullanılan bir özelliktir. Sealed sınıflar, alt sınıfların oluşturulmasını ve bu sınıflardan türetilmelerini önler. Yani, bir sınıfı sealed olarak işaretlerseniz, başka bir sınıfın bu sınıftan türemesine izin vermezsiniz.
- Sealed sınıflar genellikle, tamamen oluşturulmuş ve genişletilmesine veya değiştirilmesine ihtiyaç duyulmayan sınıflar için kullanılır. Bu, sınıfın davranışını veya yapısını değiştirmemeyi ve sağlam bir şekilde korumayı amaçlayan tasarım kararlarında kullanışlı olabilir.
- Bir sınıfı sealed olarak işaretlemek, kodunuzun belirli bir noktada kesintiye uğramasını engellemeye yardımcı olabilir. Sealed sınıflar aynı zamanda performans açısından da iyileştirme sağlayabilir, çünkü C# derleyicisi, sealed sınıfların daha verimli bir şekilde optimize edilebileceğini bilir.
- Sonuç olarak, sealed sınıflar C# dilinde miras alınmasını engelleyen sınıflardır. Bu özellik, kodunuzun sağlamlığını korumak ve belirli bir tasarımı güvence altına almak için kullanılabilir.
- Detaylı kaynak; https://www.borakasmer.com/cda-sihirli-sealed-keywordu/
- C# 9.0 ile birlikte gelen "record" sınıfı, sadece veri taşıyan ve genellikle değişmez olan veri yapılarını temsil etmek için kullanılan bir sınıf türüdür. "record" sınıfları, değer nesneleri (value objects) olarak adlandırılan ve özellikleri üzerinden eşitlik ve eşleştirme gibi işlemler gerçekleştiren sınıfları tanımlamak için kullanılır.
- "record" sınıfları, verileri depolamak için otomatik olarak gerekli tüm kodu oluştururlar. Bu, özellikleri tanımlarken getter ve setter gibi ayrı kodları yazmanıza gerek kalmadan basit bir şekilde özellikleri belirtebileceğiniz anlamına gelir. Ayrıca, "record" sınıfları varsayılan olarak "değer eşitliği" (value equality) olarak adlandırılan işlemleri destekler. Yani, iki "record" nesnesi aynı değere sahipse, bunlar eşit olarak kabul edilir.
- Aşağıda basit bir "record" sınıfı örneği verilmiştir:
public record Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
public int Age { get; init; }
}
- Yukarıdaki örnekte, "Person" sınıfı, bir kişinin adını, soyadını ve yaşını depolayan bir "record" sınıfıdır. "init" özelliği, özelliklerin sadece başlatıcı tarafından ayarlanabileceğini belirtir, yani sınıf oluşturulduktan sonra değerleri değiştirilemez.
- "record" sınıfları, özellikleri üzerinden desen eşleştirmesi (pattern matching) gibi işlemleri kolaylaştırır ve hızlıca verileri kopyalayıp değiştirmenizi sağlar. Ayrıca, "record" sınıfları, diğer sınıflarla birlikte kullanıldığında kodun daha okunabilir ve sürdürülebilir olmasını sağlayabilir.
- Bu nedenlerle, C# "record" sınıfları genellikle verileri taşımak, eşleştirmek ve karşılaştırmak için kullanılan basit veri yapısı sınıflarını tanımlamak için tercih edilir.
-
CQRS, "Command Query Responsibility Segregation" (Komut Sorgu Sorumluluğu Ayrımı) kelimelerinin baş harflerinden oluşan bir tasarım desenidir. Bu desen, bir uygulama veya sistemdeki komutları (command) ve sorguları (query) ayrı ayrı ele almayı önerir.
-
Geleneksel bir mimaride, komutlar ve sorgular genellikle aynı veri modelini kullanır ve aynı arayüzleri kullanarak veriye erişirler. Ancak CQRS deseninde, komutlar ve sorgular ayrı ayrı ele alınır ve farklı modeller ve mekanizmalar kullanılır.
-
CQRS deseninde, komutlar veri üzerinde değişiklik yapmak için kullanılır. Bunlar genellikle veri ekleme, güncelleme veya silme gibi işlemleri temsil eder. Komutlar, işlem sonrası geri bildirim veya asenkron olaylar yoluyla sonuç döndürebilir.
-
Sorgular ise veriye erişmek ve okumak için kullanılır. Sorgular, genellikle veriyi sorgulama, filtreleme ve görüntüleme gibi işlemleri gerçekleştirmek için kullanılır. Sorgular, performans ve ölçeklenebilirlik açısından optimize edilmiş ayrı bir veri modeli kullanabilir.
-
CQRS deseni, bir uygulamanın karmaşık işlemleri ve veri erişimi gerektiren senaryolarında kullanışlı olabilir. Özellikle büyük ve karmaşık sistemlerde, okuma ve yazma işlemlerinin farklı gereksinimlere sahip olduğu durumlarda CQRS deseni kullanılabilir. Bu desen, sistem performansını artırabilir, ölçeklenebilirliği iyileştirebilir ve kod tabanını daha modüler hale getirebilir.
-
Ancak CQRS deseni, uygulama geliştirme sürecindeki karmaşıklığı artırabilir ve gereksinimleri daha iyi anlamayı gerektirebilir. Bu nedenle, kullanılacağı senaryolar dikkatlice değerlendirilmeli ve doğru bir şekilde uygulanmalıdır.
-
DDD (Domain-Driven Design), yazılım geliştirme sürecinde bir tasarım yaklaşımı ve bir dizi prensiptir. DDD'nin temel amacı, karmaşık iş mantığını ve etkileşimleri içeren bir yazılımın anlaşılabilir, sürdürülebilir ve esnek bir şekilde geliştirilmesini sağlamaktır.
-
DDD'nin kullanımı, bir yazılım projesindeki temel iş alanı (domain) kavramlarına odaklanmayı ve bu kavramları yazılım modeline doğru şekilde yansıtmayı hedefler. İş alanı, bir organizasyonun ana faaliyetlerini ve süreçlerini temsil eden kritik iş kurallarını içerir. DDD, bu iş kurallarını ve iş süreçlerini anlamaya, modellemeye ve uygulamaya yönelik bir metodoloji sunar.
-
DDD'nin sağladığı faydalar şunlardır:
-
Derin iş anlayışı: DDD, proje paydaşları arasında ortak bir dil oluşturmayı teşvik eder. Bu, işin gerçek dünyadaki süreçlerini ve gereksinimlerini anlamaya yönelik derin bir iş anlayışının geliştirilmesini sağlar. Böylece, yazılım modeli işin gerçek ihtiyaçlarını doğru bir şekilde yansıtabilir.
-
Esneklik ve evrilebilirlik: DDD, yazılımın evrimsel olmasını sağlar. İş mantığındaki değişiklikler, yazılım modelinde yapılan değişikliklerle uyumlu olacak şekilde kolayca gerçekleştirilebilir. DDD'nin bileşenler arasındaki net sınırlarının ve iyi tanımlanmış bağlantılarının olması, değişikliklerin diğer bileşenlere minimum etkisini sağlar.
-
Daha iyi modülerlik: DDD, iş domainini ve bileşenlerin sorumluluklarını net bir şekilde tanımlar. Bu, yazılımın modüler bir yapıya sahip olmasını sağlar. Modülerlik, bileşenlerin bağımsız olarak geliştirilmesini, test edilmesini ve sürdürülmesini kolaylaştırır.
-
Test edilebilirlik: DDD, iş domainindeki iş kurallarını açık bir şekilde ifade etmeyi teşvik eder. Bu, iş kurallarının doğru bir şekilde test edilmesini sağlar. DDD, test edilebilirlik için mocklama ve taklit (stub) gibi teknikleri destekler.
-
Ekip işbirliği: DDD'nin ortak bir dil ve net bir iş domaini modeli sağlaması, ekipler arasında daha iyi bir işbirliği sağlar. İş süreçlerini anlamak ve yazılım modelini paylaşmak, iş analistleri, geliştiriciler ve diğer paydaşlar arasında etkili bir iletişimi teşvik eder.
-
DDD, karmaşık iş mantığını yönetmek için bir dizi prensip, tasarım deseni ve teknik sağlar. Bu yaklaşım, yazılım projelerinin başarılı bir şekilde geliştirilmesi ve sürdürülmesi için değerli bir araçtır.
- Hazırlanıyor...
-
Aggregate kökü (Aggregate Root), bir yazılım sistemi içindeki nesnelerin hiyerarşik ilişkilerinin yönetildiği bir kavramdır. Bu kavram, Domain Driven Design (DDD) adı verilen bir yazılım tasarım yaklaşımının bir parçasıdır.
-
Aggregate, birbirleriyle yakından ilişkili olan nesnelerin bir gruplamasıdır. Aggregate Root ise bu gruplamadaki ana veya kök nesnedir. Bir Aggregate Root, bir Aggregate içinde diğer nesnelerle etkileşim kurabilen ve onları yöneten bir nesnedir. Diğer nesneler, sadece Aggregate Root üzerinden erişilebilir ve bu sayede Aggregate'ın tutarlılığı korunur.
-
Aggregate Root'un birkaç önemli işlevi vardır:
-
Tutarlılık sağlama: Aggregate Root, içindeki diğer nesnelerin durumunu yöneterek, Aggregate'ın tutarlılığını korur. Yani, Aggregate'ın bileşenleri arasındaki ilişkileri kontrol eder ve Aggregate'ın bütünlüğünü sağlar.
-
İşlem sınırlarını tanımlama: Aggregate Root, Aggregate içindeki işlemlerin sınırlarını belirler. Diğer nesneler yalnızca Aggregate Root üzerinden erişilebildiği için, Aggregate'ın dışındaki nesneler doğrudan değiştirilemez veya etkileşimde bulunamaz. Bu, Aggregate'ın bütünlüğünü korumaya yardımcı olur ve sistemdeki yanlışlık riskini azaltır.
-
Nesneler arasında birbirine bağlılık sağlama: Aggregate Root, içindeki diğer nesnelerin birbirleriyle ilişkili olduğu bir yapı sağlar. Nesneler arasındaki bağlantıları yönetir ve bu bağlantıların tutarlı kalmasını sağlar.
-
Aggregate Root, bir yazılım sistemindeki karmaşayı azaltmak ve sistemdeki nesnelerin düzenlenmesini ve yönetilmesini kolaylaştırmak için kullanılır. DDD'nin temel prensiplerinden biridir ve yazılım tasarımında Aggregate'ların doğru şekilde tanımlanması ve kullanılması önemlidir.
-
Örnek;
-
Varsayalım ki bir müşteri (Customer) ve bu müşterinin siparişleri (Order) adında iki sınıfımız var. Bu iki sınıf arasında Aggregate Root ilişkisi bulunacak.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
// Diğer özellikler
// Customer sınıfı, Order nesnelerinin bir koleksiyonunu içeriyor
public ICollection<Order> Orders { get; set; }
// Aggregate Root işlemleri
public void PlaceOrder(Order order)
{
// Siparişin geçerli olup olmadığını kontrol etme
// Diğer işlemler
Orders.Add(order);
}
public void CancelOrder(Order order)
{
// Siparişin iptal işlemleri
// Diğer işlemler
Orders.Remove(order);
}
}
public class Order
{
public int Id { get; set; }
public DateTime OrderDate { get; set; }
// Diğer özellikler
}
-
Yukarıdaki örnekte Customer sınıfı, Aggregate Root rolünü üstleniyor. Orders koleksiyonu üzerinden Customer'ın ilişkili olduğu Order nesnelerine erişim sağlanıyor. Customer sınıfı, PlaceOrder ve CancelOrder gibi işlemleri gerçekleştirerek Aggregate Root'un tutarlılığını sağlıyor.
-
Bu örnekte, Aggregate Root olan Customer sınıfı üzerinden Order nesneleri yönetiliyor. Order nesneleri, Customer sınıfının içindeki Orders koleksiyonuna eklenip çıkarılıyor. Bu şekilde Aggregate Root ilişkisi ve tutarlılık sağlanmış oluyor.
-JWT, kimlik doğrulama ve yetkilendirme için kullanılan bir token formatıdır.
JWT Yapısı
Header
JWT'nin imzalanması/şifrelenmesinde kullanılan algoritmayı içerir, genellikle HMAC SHA-256 veya HS256 olarak ayarlanır.
Payload(veri taşıyıcı)
Gerçek verileri içerir. Bu veriler, JSON formatında key-value çiftleri olarak temsil edilir.
Signature
İmza, header ve payload'ın birleştirilmesiyle oluşturulan bir koddur. İmza, headerda belirtilen algoritmaya göre oluşturulur. İmzanın doğrulanmasıyla, JWT'nin bütünlüğü sağlanır ve içerdiği verilerin güvenilirliği sağlanır.
-JWT, kimlik doğrulama (authentication) ve yetkilendirme (authorization) süreçlerinde kullanılır. Bir kullanıcı oturum açtığında, sunucu tarafından verilen bir JWT ile kullanıcının kimliği doğrulanır ve bu token, kullanıcının her isteğinde sunucuya gönderilerek yetkilendirme işlemleri gerçekleştirilir. Kaynak sunucusu, JWT'yi doğrulamak zorundadır.
-OAuth, kullanıcıların bir uygulamaya erişim yetkisi verme ve yetkilendirme işlemlerini sağlayan bir protokoldür.Örneğin, bir kullanıcının Facebook hesabını kullanarak başka bir uygulamaya erişim sağlamak istediğinde, OAuth protokolü kullanılarak yetkilendirme sağlanır.
- Value Object, değeri üzerinden karşılaştırılan ve değişmez bir yapıdır, referansı yoktur. Örneğin, tarih veya para birimi.
- Reference Object, bellekte referansa sahip nesnelerdir ve kimlikleri vardır. Değişebilirler.
- Entity, benzersiz bir kimliğe sahip olan ve yaşam döngüsü boyunca değişen bir nesnedir. Örneğin, bir kullanıcı veya bir sipariş.
- Event Sourcing, verilerin her değişikliğinin olaylar (events) aracılığıyla kaydedildiği bir tasarım desenidir. Bu olaylar daha sonra geçmiş durumun yeniden oluşturulması veya analiz için kullanılabilir.
- RabbitMQ Exchange, mesajların kuyruklara yönlendirildiği bir aracıdır. Exchange tipleri şunlardır: direct, fanout, topic, headers.
- Fair Dispatch, çoklu tüketiciye sahip bir RabbitMQ kuyruğunda mesajların adil bir şekilde dağıtılması anlamına gelir. Bunu sağlamak için, "prefetch count" ayarını kullanabilirsiniz. Detaylandırmak sizin elinizde.
- Builder Tasarım Deseni, karmaşık nesnelerin oluşturulmasını basitleştirmek için kullanılır. Nesne oluşturma adımlarını ayırarak ve ardışık bir şekilde yapılandırarak kullanılır.
- Specification Tasarım Deseni, belirli bir kriteri karşılayan nesneleri filtrelemek veya seçmek için kullanılır. Özellikle sorgulamalarda ve filtrelemelerde kullanışlıdır.
- Factory Tasarım Deseni, nesne oluşturmayı merkezileştirir ve farklı alt sınıf türlerini döndürmek için kullanılır. Nesne oluşturma sürecini soyutlar.
- Saga, birçok adımdan oluşan işlemleri birden fazla servis arasında koordine etmek için kullanılan bir desen veya modeldir. Dağıtık işlemlerin güvenli ve tutarlı bir şekilde yürütülmesini sağlar.
- ConcurrentBag, çoklu iş parçacığı tarafından erişilen bir koleksiyon türüdür ve özellikle paralel programlamada kullanılır. Ekleme ve çıkarmaları destekler.
- Kilitleme, çoklu iş parçacığı tarafından aynı anda erişilen kritik bölgeleri korumak için kullanılır. Özellikle paylaşılan verilere güvenli erişim sağlamak için kullanılırım. Örneğin, Monitor veya Mutex kullanabilirsiniz.
Thread Safe – ConcurrentQueue, ConcurrentDictionary, ConcurrentBag, ConcurrentStack ve BlockingCollection Koleksiyonları hakkında neler biliyorsunuz?
- Bu koleksiyonlar, çoklu iş parçacıkları arasında veri paylaşımını güvenli bir şekilde sağlayan koleksiyon türleridir. İş parçacıkları arasında eşzamanlı erişimi desteklerler.
- Asenkron programlama, uzun süren işlemleri engellemeden çalıştırmak için kullanılır. Özellikle kullanıcı arayüzü etkileşimi gibi durumlarda yanıt süresini artırır.
- ORM (Object-Relational Mapping), nesne tabanlı programlama dilleri ile ilişkisel veritabanları arasında veri dönüşümünü kolaylaştıran bir yazılım teknolojisidir. .NET/.NET Core'da Entity Framework ve NHibernate gibi ORM teknolojileri yaygın olarak kullanılır.
- Hangfire, .NET tabanlı uygulamalar için planlanmış görevlerin ve arka plan işlemlerinin yönetimi için kullanılan bir açık kaynaklı bir kütüphanedir. Görevlerin otomatik olarak çalıştırılması ve izlenmesini sağlar.
- CI/CD (Continuous Integration/Continuous Delivery), yazılım geliştirme süreçlerinde sürekli entegrasyon ve sürekli dağıtım uygulamalarını ifade eder. Sürekli entegrasyon, yazılım değişikliklerinin sürekli olarak ana koda entegre edilmesini içerir. Sürekli dağıtım, yazılımın sürekli olarak kullanılabilir durumda olmasını sağlar.
- Bu soruya özel deneyiminizi belirtmeniz gerekecektir. .NET platformunda yaygın olarak kullanılan test framework'leri arasında NUnit, xUnit ve MSTest bulunur.
- IoC (Inversion of Control), yazılım bileşenlerinin nasıl birbirleriyle etkileşime geçeceğinin yönetildiği bir tasarım prensibidir. Geleneksel yaklaşımda bileşenler birbirlerine doğrudan bağımlıdır, ancak IoC'de bu bağımlılık tersine çevrilir ve bileşenlerin kontrolü dışarıdan sağlanır. Bu, yazılımın daha esnek, test edilebilir ve bakımı kolay hale gelmesini sağlar.
-
Docker, uygulamaları konteynerlere paketlemek ve dağıtmak için kullanılan bir konteynerleştirme platformudur. Konteynerler, bir uygulamanın çalışması için gereken tüm bağımlılıkları içeren taşınabilir ve izole edilmiş bir ortam sağlar. Docker, bir uygulamanın birden fazla ortamda sorunsuz bir şekilde çalışmasını sağlar ve sunucu, masaüstü ve bulut gibi farklı platformlarda çalışabilen hafif ve hızlı konteynerler oluşturur.
-
Docker Compose ise Docker konteynerlerinin yönetimi için kullanılan bir araçtır. Docker Compose, tek bir yerde birden fazla konteyneri tanımlamak ve bunları bir arada çalıştırmak için YAML tabanlı bir dosya formatı kullanır. Bu dosya, birden fazla konteynerin oluşturulmasını, yapılandırılmasını ve birbirleriyle etkileşimini tanımlar. Docker Compose, çok bileşenli uygulamaları kolayca çalıştırmak ve yönetmek için kullanılır.
-
Özetle, Docker konteynerlerinin oluşturulması ve yönetimi için Docker kullanılırken, Docker Compose ise birden fazla konteynerin bir arada çalıştırılmasını ve yönetilmesini sağlar. Docker Compose, konteyner tabanlı uygulamaların hızlı ve tutarlı bir şekilde dağıtılmasını kolaylaştırır.
- "Pass by value" (değer ile geçiş) ve "pass by reference" (referans ile geçiş), bir programlama dilinde bir fonksiyona veya metoda argümanların nasıl iletilip geçirildiğini ifade eden iki kavramdır.
Pass by Value (Değer ile Geçiş):
Bu yaklaşıma göre, bir fonksiyona veya metoda argüman olarak bir değer geçirilir.
Fonksiyon içinde bu değerin bir kopyası kullanılır ve fonksiyonun içinde yapılan değişiklikler, orijinal değeri etkilemez.
Java gibi dillerde genellikle bu yaklaşım kullanılır.
Pass by Reference (Referans ile Geçiş):
Bu yaklaşıma göre, bir fonksiyona veya metoda argüman olarak bir referans geçirilir. Bu referans, aslında orijinal değişkenin bellek adresini gösterir.
Fonksiyon içinde bu referans aracılığıyla orijinal değişkenin değerleri değiştirilebilir.
Örneğin, C++ gibi dillerde referans kullanılarak bu tür bir geçiş sağlanabilir.
- Default (Package-Private): Eğer bir üye (field, metod, sınıf) hiçbir access modifier belirtilmeden tanımlanırsa, bu üye o paket içindeki diğer sınıflar tarafından erişilebilir. Yani, aynı paket içindeki diğer sınıflar bu üyelere erişebilir, ancak paket dışındaki sınıflar erişemez.
- Protected: Eğer bir üye "protected" olarak tanımlanırsa, o üye hem aynı paket içindeki sınıflar hem de o sınıftan türetilen diğer sınıflar tarafından erişilebilir. Yani, hem aynı paket içindeki sınıflar hem de başka paketlerden türetilmiş sınıflar erişebilir, ancak bu sınıfların örneğinden doğrudan erişim izni yoktur.
- Primary key tabloda sadece bir adet olabilir. Unique key ise tabloda birden fazla olabilir.
- SOAP, internet üzerinden küçük miktarda bilgileri aktarma protokolüdür. XML formatındadır. REST ise, istemci ve sunucu arasında veri alışverişinin basit bir yoludur. XML, JSON, Text gibi formatlarda bu alışverişi yapabilir. SOAP'a göre daha hızlıdır.
- DELETE işlemi ile identity yok olmaz ve WHERE koşulu ile birlikte kullanabiliriz. Ancak TRUNCATE ile identity de silinir ve WHERE koşulu ile kullanılamaz.
- String objesi değişmeyen, immutable bir nesnedir ve "+" ile yeni bir karakter eklendiğinde her defasında yeni bir String nesnesi yaratılır. StringBuilder ise bir kez yaratılır ve daha sonra yeni veriler buna eklenir. Bu nedenle StringBuilder sınıfının String sınıfına göre ciddi performans üstünlüğü bulunmaktadır. Ama temel olarak StringBuilder, String değişkeninin sahip olduğu metot ve özelliklere sahiptir.
- Veritabanı tablolarındaki veriler sorgulandığında daha az veri okuyarak çok daha hızlı şekilde veriye ulaşıp sonucu döndüren yapılardır. Zaman maliyetini düşürür.
- Heap üzerinde oluşturulmuş objelere yapılmış referansları takip edip belli durumlarda kullanım dışı kalanları bellekten uçuran yapıdır.
- Inner Join: İki tabloda eşleşen kayıtlar için kullanılır.
- Left Join: İki tabloda eşleşen ve eşleşmeyen sol kayıtlar için kullanılır.
- Right Join: İki tabloda eşleşen ve eşleşmeyen sağ kayıtlar için kullanılır.
- Full Join: İki tabloda eşleşen ve eşleşmeyen sol ve sağ kayıtlar için kullanılır.
- Request, servise ulaşıyor mu diye geliştirici seçeneklerindeki Network başlığı altında kontrol edilir. Eğer ulaşıyor ise yanıt dönüyor mu ya da ne yanıt dönüyor incelenir. Ayrıca, cacheleme(ön bellekleme yapmak) veya SQL sorgularını optimize etmek de sorunu çözmeye yardımcı olabilir.