Java Günlüğüm
Yazılım, Java, BT, azıcık felsefe, biraz mizah...
  • Udemy Eğitimleri
  • Temiz Kod
  • Tasarım Kalıpları
  • Hakkımda
  • Arşiv
RSS
28 Ocak 2015

Tasarım Kalıpları – V: Singleton (Tek Nesne) – II ve Double-Checked Locking

Akin Java, Tasarım Kalıpları, Yazılım Modelleme Desen, Kalıp, Şablon, tasarım deseni, tasarım desenleri, tasarım şablonu, tasarım şablonu nedir

Tasarım kalıpları dizisinin bir önceki yazısında, ilk kalıbımız olarak Singleton’u ele almıştık. Aslında Singleton kalıbı başlangıç itibariyle kolay ve kısa olmasına rağmen, üzerinde yapılacak ufak bir oynamayla son derece karmaşık hale gelebilir. Bu yazıda da Singleton tasarım kalıbı üzerine yapılacak bu ufak değişikliğin ne olduğunu ve nasıl sonuçları olduğunu ele alalım.

Singleton kalıbımızın kodu şöyleydi:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class Singleton {
	
	private static Singleton singleton = new Singleton();
	
	private static int count;
	private String name;

	private Singleton() {
		count++;
		name = "Singleton" + count;
	}

	public static Singleton getInstance() {
		return singleton;
	}

	public void printName() {
		System.out.println(name);
	}
}

Yukarıdaki örnekteki problem, Singleton sınıfı yüklenirken “private static Singleton singleton = new Singleton();” satırının çalışması ve hiç kullanılmayacak olsa bile Singleton’un tek nesnesini yaratmasıdır. Özellikle bellek açısından ciddi kaynak tüketecek kadar büyük ve karmaşık olan nesnelerin oluşturulmasını, gerçekten erişilinceye kadar geciktirebiliriz. Bu şekilde, bir nesnenin oluşturulmasının istenildiği ana kadar geciktirilmesine, “sonradan yükleme” ya da “lazy loading” denir. Bunun tersi, yani yukarıdaki durum ise “önden yükleme” ya da “eager loading” olarak adlandırılır. Sonradan yüklemeyi kullandığımız durumda şöyle bir yapıya ulaşırız:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class LazySingleton {

	private static LazySingleton singleton;
	
	private static int count;
	private String name;

	private LazySingleton() {
		count++;
		name = "LazySingleton" + count;
	}

	public static LazySingleton getInstance() {
		if(singleton == null)
			singleton = new LazySingleton();
		return singleton;
	}

	public void printName() {
		System.out.println(name);
	}
}

Yukarıdaki sınıftaki singleton nesne, LazySingleton sınıfından üretilmektedir ve koddan da görüldüğü gibi tek nesnenin oluşturulması, “getInstance()” metodunun çağrısına kadar geciktirilmektedir. Bu yüzden tek nesne, bu metot çağrılmadıkça oluşmayacaktır, ilk defa metot çağrıldığında nesne oluşacak, sonraki çağrılarda ise bu meottaki “singleton == null” ifadesi false döneceğinden, tek nesne doğrudan metottan döndürülecektir.

Bu ikinci tip singleton yani LazySingleton, son derece şık duruyor ama çok ciddi bir yanlışı var. LazySingleton, bu haliyle birden fazla kanalın (multi-threaded) olduğu durumlarda tek nesne olmaktan çıkacak, birden fazla nesnesi oluşabilecektir. Yani, birden fazla kanal aynı anda “getInstance()” metodunu çağırırsa, bu kanalların hepsi aynı anda tek nesnenin null olduğunu görüp, birer nesne oluşturulmasına sebep olabilir. Bu durumu görmek için aşağıdaki örneğe bakalım:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class ThreadedLazySingleton {

	private static ThreadedLazySingleton singleton;

	private static int count;
	private String name;

	private ThreadedLazySingleton() {
		name = "ThreadedLazySingleton" + count;
		count++;
	}

	public static ThreadedLazySingleton getInstance() {
		if (singleton == null) {
			try {
				Thread.currentThread().sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			singleton = new ThreadedLazySingleton();
		}
		return singleton;
	}

	public void printName() {
		System.out.println(name);
	}
}

Birden fazla kanal oluşturan aşağıdaki istemciyi çalıştırırsak göreceğiz ki birden fazla ThreadLazySingleton nesnesi oluşacaktır. (Yukarıdaki örnekte “getInstance()” metodundaki “sleep()” metodu o anda çalışan kanalı 1 ms. uyutmak için konumştur ve tek amacı aynı anda birden fazla kanalın “singleton” nesnesini oluşturması ihtimalini arttırmak içindir.)

package org.javaturk.dp.pattern.gof.creational.singleton;

public class ThreadedLazySingletonClient extends Thread {

	public static void main(String[] args) {
		for(int i = 0; i < 10; i++){
			new ThreadedLazySingletonClient().start();
		}
	}
	
	public void run(){
		ThreadedLazySingleton ls = ThreadedLazySingleton.getInstance();
		ls.printName();
	}
}

Bu durumu yani birden çok “tek nesne” oluşmasını önlemek için tabi olarak “getInstance()” metodunu synchronized yapmalıyız. Bu metodu “public static synchronzied ThreadedLazySingleton getInstance()” olarak tanımladığımızda, ThreadedLazySingletonClient istemcisi kaç kanal oluşturursa oluştursun, sadece ilk kanal tek nesnenin oluşmasına sebep olacak, diğerleri ancak ilk kanal”getInstance()” metot çağrısını bitirdikten sonra aynı metodu çağırabileceğinden, tek nesne üzerinde null kontrolü artık false dönecektir. Çünkü synchronized anahtar kelimesi, “getInstance()” metodunu thread-safe hale getirecektir.

synchronized anahtar kelimesi ile thread-safe hale getirilen ThreadedLazySingleton sınıfın problemi, “getInstance()” metodunun sürekli olarak synchronized anahtar kelimesinin getirdiği kontrollerden dolayı yavaş çalışmasıdır. Bildiğiniz gibi, Java’da bu anahtar kelimeyi sadece metotlara değil, metot içindeki bloklara da uygulayabiliriz. Yani bu metodu aşağıdaki gibi sadece bir bloğunu thread-safe hale getirerek kullanabiliriz. Thread-safe hale getirdiğimiz ThreadedLazySingleton sınıfın bir metodu olduğundan dışlayıcı kilit (mut-ex lock) olarak ThreadedLazySingleton sınıfın “class” nesnesini kullanmalıyız.

public static ThreadedLazySingleton getInstance() {
      synchronized(ThreadedLazySingleton.class){
           if (singleton == null) {
		try {				   
                   Thread.currentThread().sleep(1);
		} catch (InterruptedException e) {
		   e.printStackTrace();
		}
		singleton = new ThreadedLazySingleton();
           }
      }
      return singleton;
}

Yukarıdaki kod ile aslında çok da fazla bir performans kazanımında bulunmadık çünkü if içindeki “singleton == null” kontrolü, bu metodun her çağrılışında, hem de synchronized olarak çalışıyor. Yani “singleton == null” kontrolünün thread-safe olarak çalışması gereken zaman aslında “singleton” tek nesnesinin oluşturulmasından önce olan zamandır. Bu nesne henüz oluşturulmadan, bütün “singleton == null” kontrolleri thread-safe olarak yapılmalı ama bir defa oluşturulduğunda yani “singleton = new ThreadedLazSingleton()” satırı çalıştığında, artık “singleton == null” kontrolünün synchronzied olarak olmasına gerek yoktur. Buradan şu sonuç çıkar: Eğer tek nesnenin oluşturulmasını sonradan yüklemeyle yapmak ama aynı zamanda performanslı olmasını istiyorsak, “singleton == null” kontrolünü, birisi çok kanallı, diğeri thread-safe halde iki defa yapmalıyız. Bu durumda kodumuz şu hale gelecektir:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class ThreadSafeLazySingleton {

	private static ThreadSafeLazySingleton singleton;

	private static int count;
	private String name;

	private ThreadSafeLazySingleton() {
		name = "ThreadSafeLazySingleton" + count;
		count++;
	}

	public static ThreadSafeLazySingleton getInstance() {

		if (singleton == null) {
			synchronized (ThreadSafeLazySingleton.class) {
				if (singleton == null) {
					try {
						Thread.currentThread().sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					singleton = new ThreadSafeLazySingleton();
				}
			}
		}
		return singleton;
	}

	public void printName() {
		System.out.println(name);
	}
}

Bu son durumda istemcimiz benzer şekilde şöyledir:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class ThreadSafeLazySingletonClient extends Thread{
	
	public static void main(String[] args) {
		for(int i = 0; i < 10; i++){
			new ThreadSafeLazySingletonClient().start();
		}
	}
	
	public void run(){
		ThreadSafeLazySingleton ls = ThreadSafeLazySingleton.getInstance();
		ls.printName();
	}
}

Son durum olan ThreadSafeLazySingleton sınıfının “getInstance()” metodunda “singleton == null” kontrolünün iki defa yapılmasından dolayı bu yaklaşıma double- checked locking kalıbı denir.

Double-checked locking, bir kalıp ya da ters-kalıp (anti-pattern) olarak literatüre geçmiştir. Bir kalıptır çünkü çok kanallı hallerde daha etkin yazmamızı sağlar, ters-kalıptır çünkü kodumuzu karmaşıklaştırır ve… Ve’sini bir sonraki yazıda ele alalım 🙂

Toplam görüntülenme sayısı: 2560

27 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
27 Ocak 2015

Tasarım Kalıpları: Singleton (Tek Nesne) – I

Akin Java, Tasarım Kalıpları, Yazılım Modelleme Desen, design pattern, Kalıp, Şablon, singleton, tasarım, tek nesne

Tasarım kalıpları yazı serisine, ilk kalıp örneğimiz ile devam edebiliriz.

Singleton, İngilizce’de tek olan şeye verilen isimdir. Yalnız yaşayan kişiye ya da biriç gibi oyunlarda, oyunun başında elde olan bir renkten tek kağıda da singleton denir. Yazılım açısından ise singleton, bir sınıftan sadece bir nesneye sahip olmak anlamına gelir. Bu yüzden bu kalıba dilimizde “tek nesne” diyebiliriz.

Singleton kalıbı, GoF’un nesne yaratmayla ilgili “creational” kalıplarındandır. GoF singleton için şu amaç (intent) ifadesine sahiptir:

Ensure a class only has one instance, and provide a global point of access to it.

Ya da

Bir sınıfın sadece bir tane nesnesinin olduğundan emin ol ve ona global bir erişim noktası sağla.

Singleton, yazılımlarda sıklıkla karşımıza çıkan ve bir sınıftan sadece ve sadece bir tane nesnenin bulunması gereken durumlara bir çözümdür. Bir sınıftan bir tane nesne olmasından kasıt ise, herkesin istediği zaman bu sınıfın bir nesnesini oluşturmaya çalışmamasıdır, oluşturamamasıdır. “Bir sınıfın sadece bir tane nesnesinin olduğundan emin ol” ile kastedilen budur.

Böyle bir durumla çok sık karşılaşırız. Arka taraftaki sisteme erişimleri kontrol eden yapıdan sadece bir tane olması istenir. Çünkü, bu tür nesneler trafik polisi gibi geçişi kontrol ederler, arka taraftaki sistemin vereceği hizmetlerin alınmasını düzenlerler vs. Örneğin, bir sistemde var olan yazıcıların, merkezi bir yerden yönetilmeleri makul bir durumdur. Kim hangi yazıcıya erişebilir, kim hangi yazıcıdan iş istiyor, bir yazıcıdan istenen işlerin sıraya konulması ve farklı tipte kullanıcıların farklı yazıcılarda farklı basım haklarına ve sayısına sahip olması gibi ihtiyaçların olduğu durumlarda, tüm yazıcıları ve onlara gönderilen basım isteklerini yönetecek bir merkezi sistemin (print spooler gibi) olması kaçınılmazdır. Bu sistemde merkezde bulunup, bu işleri yapacak olan nesneden sadece bir tane olması istenir. Hiç bir istemci, var olan tek nesne dışında, ikinci bir nesne yaratamamalıdır.

Benzer durum, yogun veri tabanı iletişimi bulunan OLTP tipindeki sistemlerde de veri tabanı erişim yönetiminde ortaya çıkar. Veri tabanına erişmek isteyen uygulamanın, erişimi sağlayan bağlantı (örneğin java.sql.Connection) nesnesine sahip olması gereklidir. Ama uygulamanın veri tabanına erişecek kısımlarının hepsinin ayrı ayrı bağlantı oluşturması istenen bir durum değildir. Çünkü hem bağlantı oluşturmak merkezileştirilmeli hem de bağlantı oluşturmak pahalı bir iş olduğundan, bağlantılar önceden oluşturulup bir havuzda (connection pool) tutulmalıdır ki isteyene bu havuzdaki hazır bağlantılardan servis yapılabilsin. Bu yüzden, bağlantıların üretilmesi, bir havuza atılması, isteyenlere servis edilmesi, istemcilerin kullandıkları bağlantılarla işleri bittikten sonra bağlantıyı havuza geri döndürmesi vb. gibi, tüm uygulamanın bağlantılarla ilgili ihtiyaçlarının merkezi bir yerden halledilmesi, mimari olarak uygun hatta gerekli bir yöntemdir. Bu durumda da bu merkezi konumdaki sınıfın, ismi ConnectionManager olabilir örneğin, sadece ve sadece bir tane nesnesinin olması gereklidir. Birden fazla nesne olması durumunda veri tabanına erişim ile ilgili ciddi problemler ve tutarsızlıklar olacağı açıktır.

Diğer taraftan, singleton yani tek olan nesneye erişim problemi de olmamalıdır. Kalıbın amacındaki “ve ona global bir erişim noktası sağla.” ifadesi, bu erişimin her yerden yapılabilecek şekilde olması gerektiğini söylemektedir.

Şimdi bu kalıbın çözümüne geçelim. Çözümde ben Java’yı kullanacağım ve bu çözüm, aslında kalıp olarak çok basit olmasına rağmen, detay bazı noktalardan dolayı bir yazı da gerektirecek cinstendir.

Peki şimdi son derece analitik olarak yaklaşıp, “nesne yaratma”ya odaklanalım. Çünkü kalıp, nesne yaratmakla daha doğrusu nesne yaratmayı sınırlandırmakla ilgili. Java’da nesne yaratmak için (iki sınıf hariç) daima “new” anahtar kelimesini kullanır ve yapılandırıcı (constructor) çağrısı yaparız. Yani singleton olacak sınıfın ismi Singleton ise, bu sınıfın nesnesini aşağıdaki gibi yaratırız:

...
Singleton object = new Singleton();
...

Singleton sınıfından nesne oluşturmanın ifadesi yukarıdaki satır olduğuna göre, biz bu satırın çağrılmasını nasıl kısıtlarız? Yani bu satırın herhangi bir istemci sınıfta yazılmasını nasıl engelleriz? Kalıbın çözümündeki esas mekanizma bu soruya verilecek cevap ile ortaya çıkar. Çünkü herhangi bir istemci sınıf bu ifadeyi yazabilirse, çok rahatlıkla bir for döngüsü içerisinde bu sınıftan bir sürü nesne oluşturabilir. Yani, öncelikle bu sınıftan tek bir nesne oluşturulmasına değil, istemcilerin hiç nesne oluşturamamasına odaklanmamız gereklidir. Bu da ancak ve ancak yukarıdaki satırın bir istemcide yazılmasının önüne geçmekle olabilir. Dolayısıyla, Singleton sınıfının dışında herhangi bir yerde, “Singleton object = new Singleton()” yazılmasının önüne nasıl geçebiliriz?

Soru nefis değil mi? Bu gibi bulmaca cinsinden sorular, kalıpların içinde çok sıklıkla ortaya çıkar ve tam da bu yüzden kalıpları öğrenmek çok zevklidir, çünkü zekanızı zorlarsınız.

Bakın, analitik yani çözümlemeci olmanın dibine vuralım ve sırayla gidelim. Bu cümlede

  • İlk element olan “Singleton”ın yazılmamasını sağlamanın yolu bu sınıfı public yapmamaktır. Singleton sınıfı public olmazsa, hiç bir erişim niteleyici (access modifier) kullanılmaz ve bu yüzden de bu sınıf, varsayılan erişime (default access) sahip olur. Bu durumda bu sınıfa sadece ve sadece içinde bulunduğu paketten erişilebilir. İstediğimiz ise bu değildir, çünkü bu durum global erişimi engelleyen bir haldir. Dolayısıyla çözüm, Singleton sınıfını public yapmamak değildir. Bu yüzden istemcilerde “Singleton” kelimesinin yazılmasını önleyemeyiz.
  • İkinci element olan “object”, üçüncü element olan “=”, atama işlemcisi ve dördüncü element ve bir anahtar kelime olan “new” da yazılmaları engellenemeyecek olan elementler değillerdir. Bir istemcide bu üç elementi de rahatlıkla yazabilirsiniz. Yani çözüm burada da değildir.
  • Geriye yazımını kontrol edebileceğimiz sadece ve sadece beşinci element olan “Singleton()” yapılandırıcı çağrısı kalmaktadır. Yukarıdaki cümlede, Singleton sınıfı dışında herhangi bir yerde yazılmasını engelleyebileceğiniz tek kısım “Singleton()” çağrısıdır. Çünkü Java’da erişim sınırlaması sağlayan yapılar (access modifiers) temelde üye elementlere erişimi kontrol ederler. Üye elementler ise ya üye değişkenler ya da üye metotlardır. Yapılandırıcı da üye bir metot olarak bu erişim kısıtlamasına dahildir. Uzun lafın kısası, yapılandırıcıyı “private” olarak nitelerseniz, kimse “Singleton()” yapılandırıcı çağrısını yapamaz.

Bu durumda Singleton sınıfımızı şöyle tanımlayabiliriz demektir:

public class Singleton{

   private Singleton(){
      System.out.println("Creating a singleton object");
   }
}

Yukarıdaki gibi bir kod daha önce hiç görmüş müydünüz? Garip olan şey, kaş yapayım derken göz çıkarmış olmamızdır 🙂 Yani böyle bir sınıfın hiç bir nesnesini kimse oluşturamaz, değil mi? Değil, doğrusu, “yukarıdaki Singleton sınıfının nesnesini, Singleton sınıfı dışında kimse oluşturamaz” şeklindedir. Yani Singleton, kendi nesnesini oluşturabilir çünkü “private” erişim niteleyicisi, kendi sınıfı için geçerli değildir. Bu durumda sınıfımız şu hale gelecektir:

public class Singleton{

   private Singleton object = new Singleton();

   private Singleton(){
      System.out.println("Creating a singleton object");
   }
}

Yukarıdaki kodu görünce ne düşündünüz? Böyle bir kod ile nesne kavramını ne kadar iyi bildiğinizi sınayabilirsiniz. Çünkü bu kod, “imkansız” koddur, fasit dairedir, hiç bir işe yaramaz. Çünkü singleton bir nesnenin, kendi tipinden bir nesne değişkeni olamaz. Bu yüzden “private Singleton object = new Singleton();” ifadesi bu haliyle saçma bir durum oluşturmaktadır. Düşünün öyle bir nesne oluşturacaksınız ki, içinde kendi tipinde bir başka nesne (yukarıdaki örnekte “object” ile ifade edilen) olacak ve bu içindeki nesne daha önce oluşturulmuş olacak ki yeni oluşan nesnenin parçası olabilsin. Bu mümkün değildir çünkü yukarıdaki yapıya göre Singleton sınıfının nesnesi zaten Singleton sınıfı dışında bir yerde oluşturulamaz. Buradan şu sonuç çıkar, “object” ile referans verdiğimiz nesne, nesne değişkeni değil, sınıf değişkeni, yani “static” olmalıdır. Bu durumda sınıfımızın yeni hali şöyle olur:

public class Singleton{

   private static Singleton object = new Singleton();

   private Singleton(){
      System.out.println("Creating a singleton object");
   }
}

Sınıfımızın bu son hali, kalıbın amacının “Bir sınıfın sadece bir tane nesnesinin olduğundan emin ol ” kısmını karşılamaktadır. Kalıbın amacının ikinci kısmı olan “ve ona global bir erişim noktası sağla.” ise bu sınıfa konulacak ve oluşturulan “object”i servis edecek public ve static bir metotla halledilebilir. Bu durumda da sınıfımız şu hale gelmiş olur:

public class Singleton{

   private static Singleton object = new Singleton();

   private Singleton(){
      System.out.println("Creating a singleton object");
   }

   public static Singleton getInstance(){
      return object;
   }
}

Artık Singleton sınıfımız gerçekten tasarım kalıbının istediği gibi tek bir nesnesi olan ve bu nesneye global bir erişim sağlayan yapıdadır.

Yukarıdaki Singleton sınıfını, sadece tek bir nesnesinin oluşturulduğunu ispatlayacak şekilde değiştirirsek:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class Singleton {
	
	private static Singleton singleton = new Singleton();
	
	private static int count;
	private String name;

	private Singleton() {
		count++;
		name = "Singleton" + count;
	}

	public static Singleton getInstance() {
		return singleton;
	}

	public void printName() {
		System.out.println(name);
	}
}

Bu sınıfın bir de istemcisini de yazarsak:

package org.javaturk.dp.pattern.gof.creational.singleton;

public class SingletonClient {

	public static void main(String[] args) {
		for (int i = 0; i<10; i++){
			Singleton s = Singleton.getInstance();
			s.printName();
		}
	}
}

ve bu istemciyi, SingletonClient, çalışırırsak, göreceksiniz ki program konsola 10 tane “Singleton1” yazacaktır. Çünkü sadece bir nesne oluşturulmuştur çünkü o tek nesnenin ismi “Singleton1″dir.

Singleton tasarım kalıbıyla ilgili daha geniş bilgi için hem GoF kitabına hem de c2.com’a bakabilirsiniz.

Singleton tasarım kalıbı üzerine daha pek çok şey söylenebilir. Bunları da bir sonraki yazıya bırakalım.

Toplam görüntülenme sayısı: 7304

48 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
27 Ocak 2015

Tasarım Kalıpları – IV: Kalıbı Tanımlamak

Akin Java, Tasarım Kalıpları, Yazılım Modelleme

Daha önce yayınladığım ilk yazıyla tasarım kalıplarına giriş yapmış, ikinci yazıyla da tasarım kalıplarını öğrenmek üzerinde durmuştuk. Bu yazıda da tasarım kalıplarını nasıl ifade edebileceğimizi ele alalım. Sonraki yazıda da tasarım kalıpları örneklerini ele aşmaya başlarız.

Bir tasarım şablonunun temelde dört bileşeni vardır:

  • İsmi: Kalıbın ismi, o kalıbı, problemi ve çözümüyle birlikte ayırt etmemizi sağlar. Dolayısıyla kalıpların isimleri önemlidir ve genelde ilk bulanın koyduğu isimle anılır.
  • Problem: Tasarım kalıbının hangi bağlamda ve nasıl ortaya çıktığını ifade eder. Genelde sözel anlatım olarak verilir.
  • Çözüm: Tasarım kalıbının problemi nasıl çözdüğünü, bu amaçla kullandığı parçaları ve aralarındaki ilişkileri ifade eder. Çözüm, genelde UML’in class ve sequence diyagramları ile soyut olarak betimlenir, örnek bir gerçekleştirme ise C++ ya da Java gibi uygun bir nesne-merkezli dilde verilir.
  • Sonuçlar: Kalıbın sağladıklarını ifade eder. Kalıp hem bazı kazanımlar sağlar hem de bunların karşılığında bazı kayıplara sebep olur. Sonuçlar, ayrıntılı olarak bunları ifade eder.

GoF kitabında yukarıda sayılan dört bileşeni, daha detaylı bir şekilde ele almışlar ve aşağıdaki gibi bir kalıp tanımlama yapısı kullanmışlardır. Aşağıdaki listede var olanların bazıları doğrudan yukarıdaki dört maddeden birine denk gelmektedir.

  • Name (İsim): Kalıbın ismidir.
  • Intent (Amaç): Kalıbın amacıdır.
  • Problem/Motivation (Problem/Motivasyon): Kalıbın çözmeye çalıştığı, geniş bir alandaki pek çok özel problemi ifade eden ve soyut olarak tanımlanan tipik problemdir.
  • Solution/Structure (Çözüm/Yapı): Ortaya çıktığı bağlamda kalıbın verdiği çözümdür.
  • Participants and Collaborators (Katılımcılar ve Ortakları-Paydaşları) : Çözümde var olan ana nesneler ve onlarla beraber bulunan arayüz, yardımcı nesne vb. diğer yapılardır.
  • Consequences (Sonuçlar): Kalıbın sağladıklarını ifade eder.
  • Implementation (Gerçekleştirme): Kalıbın önerdiği çözümün gerçekleştirilmesidir.
  • Generic Structure (Genel Yapı): Genelde çözümün, UML’in class ve sequence diyagramları ile soyut olarak çizimidir.
  • Applicability (Uygulanabilirlik): Kalıbın uygulanabileceği bağlamları ifade eder.
  • Sample Code (Örnek kod): Gerçekleştirmeden bahsedilen ve nesne-merkezli bir dilde yazılan örnek kod parçalarıdır.
  • Known Uses (Bilinen Kullanımlar): Gerçek sistemlerde bilinen kullanımları.
  • Related Patterns (İlgili kalıplar): İlgili diğer kalıplar, aralarındaki benzerlik ve farklar ifade edilir.

GoF kitabının sonunda, kalıplar arasındaki ilişkileri şöyle bir çizimle vermişlerdir:

Kalıplar arasındaki ilişkiler

 

Bu yazıdan sonra artık tasarım kalıplarının kendilerinden bahsetmeye başlayabiliriz.

 

Toplam görüntülenme sayısı: 2049

18 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
26 Ocak 2015

İş Kuralları – Business Rules

Akin İş ve İhtiyaç Analizi analiz, business rule, iş analizi, iş kuralı

Bir işi analiz ederken, en önemli iki analiz bilgisi olarak süreçler ve bu süreçleri yönlendiren kurallar öne çıkar. Sürecin ne olduğunu biliyoruz, kabaca, bir işin sonuçlanması için baştan sona yapılması gereken eylemler bütünüdür. İş kuralı ise, bir iş yapılış şeklini etkileyen herhangi bir karardır. İngilizce’de “business rule” olarak geçen bu kavram bir süredir hem iş süreçlerimizi anlamada hem de yazılımı geliştirmede ve programlamada bize çok faydalı bir bakış açısı sunuyor.

Aslında anlamayı kolaylaştırmak istersek, kurallar, örneğin hayatın kuralları, futbolun kuralları gibi, özel bir bağlamda uyulması-uygulanması gereken ilkelerdir. Bu anlamda iş kuralları, bir kurumun iş yapışı ile ilgili ilkeler, yönergeler, prensipler vb.den oluşan soyutlamalardır. İş kuralları, işin parçasıdır, işi yönlendirir, karar mekanizmalarını çalıştırır ya da işi yapış şeklini kısıtlar. İş yapış şekillerindeki hesaplamalarda kullanılan algoritmalar ile katsayılar, oranlar vb. özel anlamı olan sayılar, limitler, sınıflandırmalar hep iş kurallarının farklı görünümleridir.

İş kuralları, en temelde kurum tarafından belirlenir. Kurumlar farklı tanımlar ve sınıflandırmalar yapar, belli standartlar ortaya koyar, bazı değerleri hesaplamak için kendine algoritmalar oluşturur, yetkilendirmeler yapar, örneğin şu roldekiler şunu yapabilir, şu roldekiler şunu yapamaz cinsinden ifadeler belirler. Ayrıca kanuni düzenlemeler, ilgili meslek odaları vb. sektördeki ortak aklı temsil eden kurumların yaptığı düzenlemeler, endüstri standartları, uluslararası kuruluşların koyduğu kurallar vs. hep iş kurallarının kaynaklarındandır.

Literatürde farklı iş kuralı sınıflandırmaları bulunabilir. En temelde, gerçekler, algoritmalar, çıkarımlar ve kısıtlardan bahsedebiliriz. Örneğin ‘Kullanıcılar sistemde TCKN ile temsil edilirler.” sonuçta bir gerçektir ve bir iş kuralıdır. Bir e-alışveriş sisteminde gönderme ücretinin nasıl hesaplanacağı sonuçta algoritmik bir iş kuralıdır. Benzer şekilde vergilendirme de basit de olsa algoritmik yapıdadır. Çıkarımlar ise daha çok bir noktada tetiklenen kurallardır. Örneğin yine bir alışveriş sisteminde bazı mallardan satın alanlar için diğer bazı malların indirimli olarak önerilmesi ya da bazı kredi kartlarıyla ödeme yapacaklar için belli ödeme şartlarının sunulması türünden, iş sürecinde tetiklenen durumlarda kullanılacak iş kuralları mevcuttur. Son tür ise kısıtlardır ve örneğin bir B2B ısmarlama sistemi için “C tipi üye iş yerleri 10.000 TL’den daha fazla cari hesap bulundurmazlar.” şeklindeki bir iş kuralı buna örnektir.

Çoğu zaman iş kuralları bu kadar basit olmaz, içinde pek çok şart cümlesini barındıran, karmaşık cümlelerden oluşur. Bu şekildeki iş kurallarını, atomik alt parçalarına bölmek anlaşılırlık ve yönetilebilirliklerini olumlu yönde etkiler. Örneğin, “Müşteri idsi olarak, eğer müşteri TC vatandaşı ise ya web servisten ya da formdan gelen TCKN atanır. Eğer müşteri TC vatandaşı değilse müşteri idsi olarak olarak müşteri numarası atanır. Burada da yine ya web servisten ya da formdan gelen müşteri numarası kullanılır.” şeklindeki bir iş kuralını şu şekilde, dört ayrı iş kuralı olarak düzenlemek daha faydalı bir sonuç verecektir:

  • TC vatandaşı olan müşterinin idsi, TCKNdir.
  • TC vatandaşı olmayan müşterinin idsi, müşteri numarasıdır.
  • TC vatandaşı olan bir müşterinin TCKNsi, formda gelmiyorsa, web servisten sorgulanır.
  • TC vatandaşı olmayan bir müşterinin numarası, formda gelmiyorsa, web servisten sorgulanır.

İş kurallarını bu şekilde yakalamanın bir kaç faydası vardır. En temel faydası, analiste, analiz malzemesi hakkında analitik düşünme imkanı sağlamasıdır. Süreçleri yakalarken, farklı mahiyette olan iş kurallarını ayrı ihtiyaç tipi olarak yakalamak, üzerinden tartışmak, dokümante edip, doğrulama ve testin konusu olarak kullanmak son derece faydalıdır. Bu anlamda iş kuralları, yazılım ihtiyaçlarını analitik olarak çözümlemenin en temel yollarındandır.

Yazılım projelerinin ihtiyaç analizi sürecinde iş kurallarını ayrı bir şekilde yakalamak için, iş kuralı şablonu oluşturumalı ve bulunan her bir iş kuralı şablon ile belgelenmelidir. Bu amaçla analiz toplantılarında iş kurallarını keşfetmek için ayrı sorular sorulmalı ve kurallar tüm detayıyla, tipleri ve istisnaları dahil olmak üzere, yakalanmalıdır. Analiz ilerledikçe bu şekilde çalışarak bir iş kuralı kataloğu oluşacaktır. Bu katalog, iş süreçleri kadar önemli bir kaynak olacaktır.

Bununla birlikte iş kuralları, yazılım sistemlerinin sıklıkla değişen kısımlarını oluştururlar. Dolayısıyla iş kurallarının analizde yakalanıp tasarımda bunlara özel olarak yaklaşılması önemlidir. Nihayetinde yazılım sistemlerinin değişmesini tetikleyen en temel etmen, iş süreçleri ve kurallarındaki değişikliklerdir. Dolayısıyla iş kurallarının bir analiz konusu olarak yakalanması ve sonrasında tasarımda benzer şekilde özel bir şekilde ele alınması ve bu şekilde kodlanması, sistemin değişebilirliğini olumlu yönde etkileyecektir. Örneğin iş kurallarının rahatça yönetiminin ve değişmesinin sağlanması için bir iş kuralı motoru (rule engine) kullanılması ya da iş kurallarının kod içinde hard-coded olmasının önüne geçilmesi amacıyla örneğin veri tabanında tutulması ve dinamik olarak oradan yüklenmesi ve yönetilmesi, hep iş kuralı merkezli bir yaklaşımın sonucudur.

Aslolan iş kuralları ile ilgili hem iş düzeyinde hem de geliştirme düzeyinde farkındalığa ve bir metodolojiye sahip olmaktır. Yukarıda bahsettiğim sınıflandırmalar ya da isimlendirmeler bu tür yaklaşımlara bir örnektir ama sonuçta yaklaşımlar sadece bunlarla sınırlı değildir.

Tüm dünyada ve ülkemizde, projelerin ezici çoğunluğunda analiz süreci en problemli olan süreçtir. Analiz sürecini, bir malumat biriktiren, yapısallıktan uzak bir çalışma olarak ele almak, çok sık görünen bir yaklaşımdır. İş kuralları merkezli yaklaşım ise bizi daha analitik bir iş ve ihtiyaç analizi sürecine doğru götürecektir.

Toplam görüntülenme sayısı: 2693

19 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
«< 25 26 27 28 29 >»

Günlüğüme Hoşgeldiniz

Bu günlükte, Yazılım Mühendisliği, Bilgi Teknolojileri, Java, kişisel gelişim ve zaman zaman da diğer konulardaki düşüncelerimi sizlerle paylaşacağım. Umarım beğenir ve hoşça vakit geçirirsiniz.

Her türlü düşüncenizi, yorum olsun, beğeni ya da eleştiri olsun, bana iletmenizi rica ediyorum sizden. Ayrıca bana akin@javaturk.org adresinden ya da Twitter'dan ulaşabilirsiniz. Videolarıma da buradan ulaşabilirsiniz.

Teşekkür ederim.

Akın Kaldıroğlu

Rahat Okumak İçin

A Decrease font size. A Reset font size. A Increase font size.

Sosyal Medya

  • Twitter
  • Facebook
  • LinkedIn
  • Youtube

Son Twitlerim

→ Takip Etmek İçin

Abone Olun

Emalinizi girerek yazılardan haberdar olun.
Loading

Son Yazılarım

  • Udemy Eğitimlerim Üzerine
  • (başlıksız)
  • Clean Code / Temiz Kod Eğitimi Udemy’de
  • Java ile Nesne-Merkezli Programlamaya Giriş Eğitimi Udemy’de
  • Selsoft Video Eğitimleri
  • Spring ile Kurumsal Yazılım Geliştirme
  • Corona Günlerinde Design Patterns
  • Corona Günlerinde Java
  • JDK 10 ve “var” Özelliği
  • Onur Özcan
  • Analist ve İş Bilgisi
  • Farklı Dillerin Bakış Açısıyla Nesne-Merkezli Programlama
  • Java Nedir?
  • Bilgi Teknolojilerinde Yetenek Yönetimi – II: Tanımlar ve Eleştiriler – I
  • Alelade Hikayeler – II: Bir Başka Performans Problemi

Yazı Kategorileri

Yazı Takvimi

Mart 2026
P S Ç P C C P
 1
2345678
9101112131415
16171819202122
23242526272829
3031  
« May    

Yazı Arşivi

Blogroll

  • Binnur Kurt'un Günlüğü
  • Ender'in Java Blogu
  • Erdem Seherler
  • Kızımın Günlüğü
  • Kurumsal Java
  • Levent Karagöl
  • Levent'in Java Blogu
  • Mert Can Akkan’s java tips,options, news…
  • Yaşar Safkan
  • Yasin Saygılı
  • Yazı Dünyası

Yazı Etiketleri

analiz Bilmek C Desen design pattern EJB Eğitim Fortran Hibernate Java Java'ya nasil baslarim Java dersleri Java EE Java Persistence API Java SE Java Sertifika Java Öğren Java öğreniyorum Java öğrenmek JPA Kalıp Kurumsal Java nesne nesne-merkezli No Silver Bullet object object-oriented Oracle Java Certifications pattern performans programlama programlama dilleri programlama nedir sertifika singleton tasarım tasarım deseni tasarım desenleri tasarım şablonu yazılım yazılım geliştirme Yazılım Mühendisliği yazılımın doğası yazılımın zorlukları Şablon

↑

© Java Günlüğüm 2026
Powered by WordPress • Themify WordPress Themes
 

Yorumlar Yükleniyor...