Bu e-kitap, back-end yazılım geliştirmede modern standartları ve en iyi uygulamaları derinlemesine inceleyen kapsamlı bir rehberdir. Amacımız, Dependency Injection'dan Domain-Driven Design'a, mikroservis mimarisinden CI/CD süreçlerine kadar geniş bir yelpazede, sağlam, ölçeklenebilir ve sürdürülebilir back-end sistemleri oluşturmak için gereken temel kavramları ve teknolojileri sunmaktır. Bu rehber, ister kariyerinin başındaki bir geliştirici olun, ister deneyimli bir mühendis, back-end dünyasındaki yetkinliklerinizi bir üst seviyeye taşımanıza yardımcı olacak.
-
Dependency Injection & IoC: Bağımlılık enjeksiyonu ve kontrolün tersine çevrilmesi prensipleri.
-
Concurrency & Parallelism: Eş zamanlılık ve paralellik kavramları arasındaki farklar ve kullanım alanları.
-
Threading vs Async Programming: Threading ve asenkron programlama yaklaşımlarının karşılaştırması.
-
Event-Driven Architecture: Olay tabanlı mimarinin temelleri ve avantajları.
-
Observer & Pub/Sub Patterns: Observer ve Yayıncı/Abone (Pub/Sub) tasarım kalıplarının kullanımı.
-
Design Patterns (OOP odaklı): Sık kullanılan nesne yönelimli tasarım kalıpları.
Singleton, Factory, Strategy, vb.
-
Clean Architecture & SOLID Principles: Temiz mimari ve SOLID prensiplerinin detaylı incelenmesi.
-
Domain-Driven Design (DDD): Etki alanına dayalı tasarımın temel prensipleri ve uygulama yöntemleri.
-
Functional Programming Concepts: Fonksiyonel programlamanın back-end geliştirmeye katkıları.
-
Reactive Programming (RxJS, Reactor, vb.): Reaktif programlama paradigmaları ve popüler kütüphaneler.
-
Microservices & API Design: Mikroservis mimarisi ve etkili API tasarımı.
-
REST vs GraphQL: REST ve GraphQL API'lerinin karşılaştırması ve seçim kriterleri.
-
Message Brokers (Kafka, RabbitMQ): Mesaj aracıları (Message Brokers) ve dağıtık sistemlerdeki rolleri.
-
Caching Strategies (Redis, CDN, vb.): Verimlilik artırıcı önbellekleme stratejileri.
-
Authentication & Authorization Concepts: Kimlik doğrulama ve yetkilendirme süreçlerinin anlaşılması.
-
Containerization & Docker Concepts: Konteynerleştirme ve Docker'ın temel kavramları.
-
CI/CD & DevOps Pipelines: Sürekli Entegrasyon ve Sürekli Dağıtım (CI/CD) süreçleri.
-
Logging & Monitoring: Etkili loglama ve sistem izleme (monitoring) uygulamaları.
-
Testing Types (Unit, Integration, E2E): Birim, entegrasyon ve uçtan uca test türleri.
-
Memory Management & Garbage Collection: Bellek yönetimi ve çöp toplama (Garbage Collection) süreçleri.
Dependency Injection (Bağımlılık Enjeksiyonu), nesnelerin kendi bağımlılıklarını (yani ihtiyaç duydukları diğer nesneleri) kendileri oluşturmak yerine, bunları dış bir kaynaktan aldığı bir tasarım desenidir. Bu yaklaşım, gevşek bağlılığı (loose coupling), daha kolay test edilebilirliği ve daha iyi kod sürdürülebilirliğini teşvik eder. Spring çatısı altında Bağımlılık Enjeksiyonu, genellikle Constructor Injection (Kurucu Metot Enjeksiyonu) veya Setter Injection (Ayarlayıcı Metot Enjeksiyonu) aracılığıyla gerçekleştirilir.
Bir A sınıfının, işlemlerini gerçekleştirmek için bir B sınıfına ait bir nesneye ihtiyacı olduğunu varsayalım. Bu, A sınıfının B sınıfına bağımlı olduğu anlamına gelir.
Böyle bir bağımlılık kabul edilebilir gibi görünse de, gerçek dünya uygulamalarında sıkı bağlılığa, bakımı zorlaştırmaya, test edilebilirliği azaltmaya veya potansiyel sistem arızalarına yol açabilir. Bu nedenle, doğrudan bağımlılıklardan kaçınılmalıdır.
Spring IoC (Kontrolün Tersine Çevrilmesi), bu tür bağımlılık sorunlarını Bağımlılık Enjeksiyonu (DI) kullanarak çözer. Bağımlılık Enjeksiyonu, kodu daha kolay test edilebilir ve yeniden kullanılabilir hale getirir.
Sınıflar arasındaki gevşek bağlılık, ortak işlevsellik için arayüzler tanımlayarak veya enjektörün (Spring container) uygun implementasyonu sağlamasına izin verilerek elde edilir. Nesneleri örneklendirme görevi, geliştiricinin belirttiği konfigürasyonlara göre container tarafından yapılır.
Spring Bağımlılık Enjeksiyonunun iki temel türü vardır:
- Setter Dependency Injection (SDI):
Setter DI, bağımlılıkların setter metotları aracılığıyla enjekte edilmesini içerir. SDI'yı yapılandırmak için, setter metotlarıyla birlikte @Autowired ek açıklaması kullanılır ve özellik, bean yapılandırma dosyasındaki etiketi aracılığıyla ayarlanır.
package com.geeksforgeeks.org;
import com.geeksforgeeks.org.IGeek;
import org.springframework.beans.factory.annotation.Autowired;
public class GFG {
// The object of the interface IGeek
private IGeek geek;
// Setter method for property geek with @Autowired annotation
@Autowired
public void setGeek(IGeek geek) {
this.geek = geek;
}
}
Bean Configuration
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="GFG" class="com.geeksforgeeks.org.GFG">
<property name="geek" ref ="CsvGFG" />
</bean>
<bean id="CsvGFG" class="com.geeksforgeeks.org.impl.CsvGFG" />
<bean id="JsonGFG" class="com.geeksforgeeks.org.impl.JsonGFG" />
</beans>
Bu, setter metodunu (setGeek) kullanarak CsvGFG bean'ini GFG nesnesine enjekte eder.
- Constructor Dependency Injection (CDI):
Constructor DI, bağımlılıkların kurucu metotlar aracılığıyla enjekte edilmesini içerir. CDI'yı yapılandırmak için, bean yapılandırma dosyasında etiketi kullanılır.
package com.geeksforgeeks.org;
import com.geeksforgeeks.org.IGeek;
public class GFG {
// The object of the interface IGeek
private IGeek geek;
// Constructor to set the CDI
public GFG(IGeek geek) {
this.geek = geek;
}
}
Bean Configuration :
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="GFG" class="com.geeksforgeeks.org.GFG">
<constructor-arg>
<bean class="com.geeksforgeeks.org.impl.CsvGFG" />
</constructor-arg>
</bean>
<bean id="CsvGFG" class="com.geeksforgeeks.org.impl.CsvGFG" />
<bean id="JsonGFG" class="com.geeksforgeeks.org.impl.JsonGFG" />
</beans>
Bu, CsvGFG bean'ini oluşturucu aracılığıyla GFG nesnesine enjekte eder.
Özellik | Setter DI | Constructor DI |
---|---|---|
Nesne Durumu | Değiştirilebilir (Mutable) nesneler oluşturur. Bağımlılıklar, oluşturulduktan sonra değiştirilebilir. | Değiştirilemez (Immutable) nesneler oluşturur. Bağımlılıklar, oluşturulduktan sonra değiştirilemez. |
Bağımlılık Zamanı | Bağımlılıklar daha sonra enjekte edilebilir. | Tüm bağımlılıklar nesne oluşturulurken sağlanmalıdır. |
Annotation Gereksinimi | @Autowired ek açıklamasının eklenmesini gerektirir. |
@Autowired ek açıklaması gerekli değildir. |
Döngüsel Bağımlılıklar | Döngüsel bağımlılıklara veya kısmi bağımlılıklara neden olabilir. | Döngüsel bağımlılıklar bunda da olabilir, ancak daha hızlı ve daha belirgin bir şekilde başarısız olur. |
Test Edilebilirlik | Testlerde bağımlılık enjeksiyonu için framework veya elle setter metot çağrıları gerektirir. | Birim testi daha kolaydır; sahte (mock) bağımlılıklarla nesneler doğrudan oluşturulabilir. |
Dört ana bileşenimiz var: IEngine arayüzü, ToyotaEngine sınıfı (IEngine'ı uygular), Tyres sınıfı ve Vehicle sınıfı (IEngine ve Tyres'a bağımlı).
Burada, Vehicle kendi bağımlılıklarını oluşturmuyor; Spring, nesne oluşturma ve bağlama işini bizim için hallediyor.
ToyotaEngine, iki Tyres örneği (tyre1Bean, tyre2Bean) ve iki Vehicle örneği için bean'ler XML konfigürasyonunda tanımlanmıştır.
İki tür bağımlılık enjeksiyonu kullanılıyor: InjectwithConstructor, etiketleri aracılığıyla kurucu enjeksiyonunu kullanırken, InjectwithSetter ise etiketleri aracılığıyla setter enjeksiyonunu kullanıyor.
Spring, konfigürasyona bağlı olarak her bir Vehicle'a hangi motoru ve lastikleri enjekte edeceğini belirliyor.
Vehicle, motorun veya lastiğin gerçek uygulamasından haberdar değildir.
Bu durum, sistemi gevşek bağlı hale getirerek bakımı kolaylaştırır, daha esnek yapar ve ana mantığı bozmadan bileşenleri değiştirmeyi basitleştirir.
interface IEngine {
String EMISSION_NORMS = "BSIV";
String importOrigin();
double cost();
}
public class ToyotaEngine implements IEngine {
String company;
double cost;
public double getCost() { return cost; }
public void setCost(double cost) { cost = this.cost; }
public String getCompany() { return company; }
public void setCompany(String company)
{
this.company = company;
}
@Override public String importOrigin()
{
return "Japan";
}
@Override public double cost() { return cost; }
@Override public String toString()
{
return "This is Engine object from: " + company;
}
}
public class Tyres {
String name;
String place;
String message;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPlace() { return place; }
public void setPlace(String place)
{
this.place = place;
}
public String getMessage() { return message; }
public void setMessage(String message)
{
this.message = message;
}
@Override public String toString()
{
return "This is Tyre object: " + name + " " + place
+ " " + message;
}
}
public class Vehicle {
IEngine engine;
Tyres tyre;
public Tyres getTyre() { return tyre; }
public void setTyre(Tyres tyre)
{
System.out.println("tyre instantiated via setter");
this.tyre = tyre;
}
public Vehicle(IEngine engine, Tyres tyre)
{
System.out.println("instantiated via constructor");
this.engine = engine;
this.tyre = tyre;
}
public Vehicle() {}
public IEngine getEngine() { return engine; }
public void setEngine(IEngine engine)
{
System.out.println("instantiated via setter");
this.engine = engine;
}
@Override public String toString()
{
return engine + " " + tyre;
}
public static void main(String a[])
{
ApplicationContext rootctx
= new ClassPathXmlApplicationContext(
"springContext.xml");
// Instantiating the obj1 via Constructor DI
Vehicle obj1 = (Vehicle)rootctx.getBean(
"InjectwithConstructor");
// Instantiating the obj1 via Setter DI
Vehicle obj2
= (Vehicle)rootctx.getBean("InjectwithSetter");
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj1 == obj2);
}
}
<dependencies>
<!-- https:// mvnrepository.com/artifact
/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
<!-- https:// mvnrepository.com/artifact
/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.11.RELEASE</version>
</dependency>
</dependencies>
< bean id="tyre1Bean" class="com.techgene.Tyres">
<property name="name" value="MRF">
</ property>
<property name="place" value="India">
</ property>
<property name="message" value="Make in India">
</ property>
</ bean>
< bean id="ToyotaBean" class="com.techgene.ToyotaEngine">
<property name="company" value="Toyota">
</ property>
<property name="cost" value="300000.00">
</ property>
</ bean>
< bean id="tyre2Bean" class="com.techgene.Tyres">
<property name="name" value="TVS">
</ property>
<property name="place" value="India">
</ property>
<property name="message" value="Make in India">
</ property>
</ bean>
< bean id="InjectwithSetter" class="com.techgene.Vehicle">
<property name="engine" ref="ToyotaBean">
</ property>
<property name="tyre" ref="tyre1Bean">
</ property>
</ bean>
< bean id="InjectwithConstructor" class="com.techgene.Vehicle">
<constructor - arg name="engine" ref="ToyotaBean">
</ constructor - arg>
<constructor - arg name="tyre" ref="tyre2Bean">
</ constructor - arg>
</ bean>